# coding: utf-8
__author__ = 'Alex Kustov, IPPM RAS'

import os

gpu_use = 0
os.environ["KERAS_BACKEND"] = "tensorflow"
os.environ["CUDA_VISIBLE_DEVICES"] = "{}".format(gpu_use)

from r04_find_optimal_bit_for_weights import *


def addressRAM(directory, steps_count, max_address_value):
    f = open(directory + "addressRAM.v", 'w')

    bit_steps_count = len(bin(steps_count)) - 2
    bit_max_address_value = len(bin(max_address_value)) - 2

    f.write("module addressRAM(\n")
    f.write("	input ["+str(bit_steps_count-1)+":0] step,\n")
    f.write("	output reg re_weights,\n")
    f.write("	output reg re_bias,\n")
    f.write("	output reg ["+str(bit_max_address_value-1)+":0] firstaddr, lastaddr\n")
    f.write(");\n")
    f.write("parameter convolution_size = 9;\n")
    f.write("parameter conv1 = 1*8*3 * convolution_size;\n")
    f.write("parameter conv2_1 = 8 * convolution_size + conv1;\n")
    f.write("parameter conv2_2 = (8*8*2) + conv2_1;\n")
    f.write("parameter conv3_1 = 16 * convolution_size + conv2_2;\n")
    f.write("parameter conv3_2 = (16*16*2) + conv3_1;\n")
    f.write("parameter conv4_1 = 32 * convolution_size + conv3_2;\n")
    f.write("parameter conv4_2 = (32*32) + conv4_1;\n")
    f.write("parameter conv5_1 = 32 * convolution_size + conv4_2;\n")
    f.write("parameter conv5_2 = (32*32*2) + conv5_1;\n")
    f.write("parameter conv6_1 = 64 * convolution_size + conv5_2;\n")
    f.write("parameter conv6_2 = (64*64) + conv6_1;\n")
    f.write("parameter conv7_1 = 64 * convolution_size + conv6_2;\n")
    f.write("parameter conv7_2 = (64*64*2) + conv7_1;\n")
    f.write("parameter conv8_1 = 128 * convolution_size + conv7_2;\n")
    f.write("parameter conv8_2 = (128*128) + conv8_1;\n")
    f.write("parameter conv9_1 = 128 * convolution_size + conv8_2;\n")
    f.write("parameter conv9_2 = (128*128) + conv9_1;\n")
    f.write("parameter conv10_1 = 128 * convolution_size + conv9_2;\n")
    f.write("parameter conv10_2 = (128*128) + conv10_1;\n")
    f.write("parameter conv11_1 = 128 * convolution_size + conv10_2;\n")
    f.write("parameter conv11_2 = (128*128) + conv11_1;\n")
    f.write("parameter conv12_1 = 128 * convolution_size + conv11_2;\n")
    f.write("parameter conv12_2 = (128*128) + conv12_1;\n")
    f.write("parameter conv13_1 = 128 * convolution_size + conv12_2;\n")
    f.write("parameter conv13_2 = (128*128*2) + conv13_1;\n")
    f.write("parameter conv14_1 = 256 * convolution_size + conv13_2;\n")
    f.write("parameter conv14_2_1 = ((256*256)>>1) + conv14_1;\n")
    f.write("parameter conv14_2_2 = ((256*256)>>1) + conv14_2_1;\n")
    f.write("parameter predict = 512 + conv14_2_2;\n")
    f.write("\n")
    f.write("\n")
    f.write("parameter bias1 = 8;\n")
    f.write("parameter bias2_1 = (8)+8;\n")
    f.write("parameter bias2_2 = (16)+16;\n")
    f.write("parameter bias3_1 = (32)+16;\n")
    f.write("parameter bias3_2 = (48)+32;\n")
    f.write("parameter bias4_1 = (80)+32;\n")
    f.write("parameter bias4_2 = (112)+32;\n")
    f.write("parameter bias5_1 = (144)+32;\n")
    f.write("parameter bias5_2 = (176)+64;\n")
    f.write("parameter bias6_1 = (240)+64;\n")
    f.write("parameter bias6_2 = (304)+64;\n")
    f.write("parameter bias7_1 = (368)+64;\n")
    f.write("parameter bias7_2 = (432)+128;\n")
    f.write("parameter bias8_1 = (560)+128;\n")
    f.write("parameter bias8_2 = (688)+128;\n")
    f.write("parameter bias9_1 = (816)+128;\n")
    f.write("parameter bias9_2 = (944)+128;\n")
    f.write("parameter bias10_1 = (1072)+128;\n")
    f.write("parameter bias10_2 = (1200)+128;\n")
    f.write("parameter bias11_1 = (1328)+128;\n")
    f.write("parameter bias11_2 = (1456)+128;\n")
    f.write("parameter bias12_1 = (1584)+128;\n")
    f.write("parameter bias12_2 = (1712)+128;\n")
    f.write("parameter bias13_1 = (1840)+128;\n")
    f.write("parameter bias13_2 = (1968)+256;\n")
    f.write("parameter bias14_1 = (2224)+256;\n")
    f.write("parameter bias14_2_1 = (2480)+(256>>1);\n")
    f.write("parameter bias14_2_2 = (2608)+(256>>1);\n")
    f.write("\n")
    f.write("\n")
    f.write("always @(step)\n")
    f.write("case (step) \n")
    f.write("8'd1: begin       //weights conv1 \n")
    f.write("		firstaddr = 0;\n")
    f.write("		lastaddr = conv1;\n")
    f.write("		re_weights = 1;\n")
    f.write("		re_bias = 0;\n")
    f.write("	  end\n")
    f.write("8'd2: begin	//bias conv1\n")
    f.write("		firstaddr = 0;\n")
    f.write("		lastaddr = bias1;\n")
    f.write("		re_weights = 0;\n")
    f.write("		re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd4: begin  //weights conv2 dw 1\n")
    f.write("		firstaddr = conv1;\n")
    f.write("		lastaddr = conv2_1;\n")
    f.write("		re_weights = 1;\n")
    f.write("		re_bias = 0;\n")
    f.write("	  end\n")
    f.write("8'd5: begin	//bias conv2 dw\n")
    f.write("		firstaddr = bias1;\n")
    f.write("		lastaddr = bias2_1;\n")
    f.write("		re_weights = 0;\n")
    f.write("		re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd7: begin //weights conv2 1x1\n")
    f.write("		firstaddr = conv2_1;\n")
    f.write("		lastaddr = conv2_2;\n")
    f.write("		re_weights = 1;\n")
    f.write("		re_bias = 0;\n")
    f.write("	  end\n")
    f.write("8'd8: begin //bias conv2 1x1\n")
    f.write("		firstaddr = bias2_1;\n")
    f.write("		lastaddr = bias2_2;\n")
    f.write("		re_weights = 0;\n")
    f.write("		re_bias = 1;\n")
    f.write("	  end\n")
    f.write("8'd10: begin //weights conv3 dw 2\n")
    f.write("		firstaddr = conv2_2;\n")
    f.write("		lastaddr  = conv3_1;\n")
    f.write("		re_weights = 1;\n")
    f.write("		re_bias = 0;\n")
    f.write("	   end\n")
    f.write("8'd11: begin //bias conv3 DW\n")
    f.write("		firstaddr = bias2_2;\n")
    f.write("		lastaddr  = bias3_1;\n")
    f.write("		re_weights = 0;\n")
    f.write("		re_bias = 1;\n")
    f.write("	   end\n")
    f.write("8'd13: begin //weights conv3 1x1\n")
    f.write("   	firstaddr = conv3_1;\n")
    f.write("   	lastaddr  = conv3_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd14: begin //bias conv\n")
    f.write("   	firstaddr = bias3_1;\n")
    f.write("   	lastaddr  = bias3_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd16: begin\n")
    f.write("   	firstaddr = conv3_2; // dw 3\n")
    f.write("   	lastaddr  = conv4_1;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd17: begin\n")
    f.write("   	firstaddr = bias3_2;\n")
    f.write("   	lastaddr  = bias4_1;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("     end\n")
    f.write("8'd19: begin\n")
    f.write("   	firstaddr = conv4_1;\n")
    f.write("   	lastaddr  = conv4_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd20: begin\n")
    f.write("   	firstaddr = bias4_1;\n")
    f.write("   	lastaddr  = bias4_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd22: begin\n")
    f.write("   	firstaddr = conv4_2; // dw 4\n")
    f.write("   	lastaddr  = conv5_1;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("     end\n")
    f.write("8'd23: begin\n")
    f.write("   	firstaddr = bias4_2;\n")
    f.write("   	lastaddr  = bias5_1;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd25: begin\n")
    f.write("   	firstaddr = conv5_1;\n")
    f.write("   	lastaddr  = conv5_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd26: begin\n")
    f.write("   	firstaddr = bias5_1;\n")
    f.write("   	lastaddr  = bias5_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd28: begin\n")
    f.write("   	firstaddr = conv5_2; // dw 5\n")
    f.write("   	lastaddr  = conv6_1;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("     end\n")
    f.write("8'd29: begin\n")
    f.write("   	firstaddr = bias5_2;\n")
    f.write("   	lastaddr  = bias6_1;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd31: begin\n")
    f.write("   	firstaddr = conv6_1;\n")
    f.write("   	lastaddr  = conv6_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd32: begin\n")
    f.write("   	firstaddr = bias6_1;\n")
    f.write("   	lastaddr  = bias6_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd34: begin\n")
    f.write("   	firstaddr = conv6_2; // dw 6\n")
    f.write("   	lastaddr  = conv7_1;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd35: begin\n")
    f.write("   	firstaddr = bias6_2;\n")
    f.write("   	lastaddr  = bias7_1;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd37: begin\n")
    f.write("   	firstaddr = conv7_1;\n")
    f.write("   	lastaddr  = conv7_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("     end\n")
    f.write("8'd38: begin\n")
    f.write("   	firstaddr = bias7_1;\n")
    f.write("   	lastaddr  = bias7_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd40: begin\n")
    f.write("   	firstaddr = conv7_2; // dw 7\n")
    f.write("   	lastaddr  = conv8_1;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd41: begin\n")
    f.write("   	firstaddr = bias7_2;\n")
    f.write("   	lastaddr  = bias8_1;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd43: begin\n")
    f.write("   	firstaddr = conv8_1;\n")
    f.write("   	lastaddr  = conv8_2;\n")
    f.write("   	re_weights = 1;\n")
    f.write("   	re_bias = 0;\n")
    f.write("      end\n")
    f.write("8'd44: begin\n")
    f.write("   	firstaddr = bias8_1;\n")
    f.write("   	lastaddr  = bias8_2;\n")
    f.write("   	re_weights = 0;\n")
    f.write("   	re_bias = 1;\n")
    f.write("      end\n")
    f.write("8'd46: begin\n")
    f.write("	    firstaddr = conv8_2; // dw 8\n")
    f.write("	    lastaddr  = conv9_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd47: begin\n")
    f.write("	    firstaddr = bias8_2;\n")
    f.write("	    lastaddr  = bias9_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd49: begin\n")
    f.write("	    firstaddr = conv9_1;\n")
    f.write("	    lastaddr  = conv9_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd50: begin\n")
    f.write("	    firstaddr = bias9_1;\n")
    f.write("	    lastaddr  = bias9_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd52: begin\n")
    f.write("	    firstaddr = conv9_2; // dw 9\n")
    f.write("	    lastaddr  = conv10_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd53: begin\n")
    f.write("	    firstaddr = bias9_2;\n")
    f.write("	    lastaddr  = bias10_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd55: begin\n")
    f.write("	    firstaddr = conv10_1;\n")
    f.write("	    lastaddr  = conv10_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd56: begin\n")
    f.write("	    firstaddr = bias10_1;\n")
    f.write("	    lastaddr  = bias10_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd58: begin\n")
    f.write("	    firstaddr = conv10_2; // dw 10\n")
    f.write("	    lastaddr  = conv11_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd59: begin\n")
    f.write("	    firstaddr = bias10_2;\n")
    f.write("	    lastaddr  = bias11_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd61: begin\n")
    f.write("	    firstaddr = conv11_1;\n")
    f.write("	    lastaddr  = conv11_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd62: begin\n")
    f.write("	    firstaddr = bias11_1;\n")
    f.write("	    lastaddr  = bias11_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd64: begin\n")
    f.write("	    firstaddr = conv11_2; // dw 11\n")
    f.write("	    lastaddr  = conv12_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd65: begin\n")
    f.write("	    firstaddr = bias11_2;\n")
    f.write("	    lastaddr  = bias12_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd67: begin\n")
    f.write("	    firstaddr = conv12_1;\n")
    f.write("	    lastaddr  = conv12_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd68: begin\n")
    f.write("	    firstaddr = bias12_1;\n")
    f.write("	    lastaddr  = bias12_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd70: begin\n")
    f.write("	    firstaddr = conv12_2; // dw 12\n")
    f.write("	    lastaddr  = conv13_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd71: begin\n")
    f.write("	    firstaddr = bias12_2;\n")
    f.write("	    lastaddr  = bias13_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd73: begin\n")
    f.write("	    firstaddr = conv13_1;\n")
    f.write("	    lastaddr  = conv13_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd74: begin\n")
    f.write("	    firstaddr = bias13_1;\n")
    f.write("	    lastaddr  = bias13_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd76: begin\n")
    f.write("	    firstaddr = conv13_2; // dw 13\n")
    f.write("	    lastaddr  = conv14_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd77: begin\n")
    f.write("	    firstaddr = bias13_2;\n")
    f.write("	    lastaddr  = bias14_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd79: begin\n")
    f.write("	    firstaddr = conv14_1;\n")
    f.write("	    lastaddr  = conv14_2_1;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd80: begin\n")
    f.write("	    firstaddr = bias14_1;\n")
    f.write("	    lastaddr  = bias14_2_1;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd82: begin\n")
    f.write("	    firstaddr = conv14_2_1;\n")
    f.write("	    lastaddr  = conv14_2_2;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("8'd83: begin\n")
    f.write("	    firstaddr = bias14_2_1;\n")
    f.write("	    lastaddr  = bias14_2_2;\n")
    f.write("	    re_weights = 0;\n")
    f.write("	    re_bias = 1;\n")
    f.write("       end\n")
    f.write("8'd85: begin\n")
    f.write("	    firstaddr = conv14_2_2;\n")
    f.write("	    lastaddr  = predict;\n")
    f.write("	    re_weights = 1;\n")
    f.write("	    re_bias = 0;\n")
    f.write("       end\n")
    f.write("default:\n")
    f.write("		begin\n")
    f.write("			re_weights = 0;\n")
    f.write("			re_bias = 0;\n")
    f.write("		end\n")
    f.write("endcase\n")
    f.write("endmodule\n")

    f.close()

def border(directory, razmer):
    f = open(directory + "border.v",'w')

    bit_matrix = len(bin(razmer))-2
    bit_matrix_2=len(bin(razmer*razmer))-2

    f.write("module border(\n")
    f.write("    input clk, go,\n")
    f.write("    input ["+str(bit_matrix_2-1)+":0] i,\n")
    f.write("    input ["+str(bit_matrix-1)+":0] matrix,\n")
    f.write("    output reg [1:0] prov\n")
    f.write(");\n")
    f.write("	always @(posedge clk)\n")
    f.write("	begin	\n")
    f.write("		if (go == 1)\n")
    f.write("		begin\n")
    f.write("			prov = 0;\n")
    for i in range(128):
        f.write("				if ((i == "+str(i+1)+"*matrix-1'b1) && (prov != 2'b10))	prov = 2'b10;\n")
    f.write("\n")
    for i in range(128+1):
        f.write("               if ((i == "+str(i)+"*matrix) && (prov != 2'b11))		    prov = 2'b11;\n")
    f.write("		end\n")
    f.write("		else\n")
    f.write("			prov = 0;\n")
    f.write("	end\n")
    f.write("endmodule\n")

    f.close()

def conv_block(directory,razmer):
    f = open(directory + "conv.v",'w')

    bit_matrix = len(bin(razmer)) - 2
    bit_matrix_2 = len(bin(razmer*razmer)) - 2

    f.write("module conv(clk,Y1,prov,matrix,matrix2,i,up_perm,down_perm,p1,p2,p3,w1,w2,w3,conv_en,dense_en,stride_plus_prov);\n")
    f.write("\n")
    f.write("parameter SIZE=0;\n")
    f.write("parameter SIZE_address_pix=18;\n")
    f.write("parameter SIZE_weights=0;\n")
    f.write("\n")
    f.write("input clk;\n")
    f.write("output reg signed [32-1:0] Y1;\n")
    f.write("input [1:0] prov;\n")
    f.write("input ["+str(bit_matrix-1)+":0] matrix;\n")
    f.write("input ["+str(bit_matrix_2-1)+":0] matrix2;\n")
    f.write("input ["+str(bit_matrix_2-1)+":0] i;\n")
    f.write("input up_perm,down_perm;\n")
    f.write("input signed [SIZE-1:0] p1,p2,p3;\n")
    f.write("input signed [SIZE_weights-1:0] w1,w2,w3;\n")
    f.write("input conv_en;\n")
    f.write("input dense_en;\n")
    f.write("input [SIZE_address_pix-1:0] stride_plus_prov;\n")
    f.write("\n")
    f.write("wire up,down;\n")
    f.write("\n")
    f.write("assign up = (((i+stride_plus_prov)<=matrix-1'b1)&&(up_perm))?1'b1:1'b0;\n")
    f.write("assign down = (((i+stride_plus_prov)>=matrix2-matrix)&&(down_perm))?1'b1:1'b0;\n")
    f.write("\n")
    f.write("always @(posedge clk)\n")
    f.write("    begin\n")
    f.write("		if (conv_en==1)\n")
    f.write("			begin\n")
    f.write("				Y1=0;\n")
    f.write("				if ((prov!=2'b11)&&(!up)&&(!down)) Y1 = Y1+(p1*w1);\n")
    f.write("				if                ((!up)&&(!down)) Y1 = Y1+(p2*w2);\n")
    f.write("				if ((prov!=2'b10)&&(!up)&&(!down)) Y1 = Y1+(p3*w3);\n")
    f.write("			end\n")
    f.write("    end\n")
    f.write("\n")
    f.write("endmodule\n")

    f.close()

def conv_TOP(directory, razmer, max_conv_input_size, max_conv_output_size, num_conv, steps_count, sizeI, sizeW):
    f = open(directory + "conv_TOP.v", 'w')

    bit_matrix=len(bin(razmer))-2
    bit_matrix_2=len(bin(razmer*razmer))-2
    bit_max_conv_input_size = len(bin(max_conv_input_size)) - 2
    bit_max_conv_output_size = len(bin(max_conv_output_size)) - 2
    bit_razmer_2 = len(bin(razmer * razmer)) - 2
    bit_steps_count = len(bin(steps_count)) - 2
    Y=''
    w=''
    p=''
    res_out=''
    res=''
    res_old=''
    glob_average_perem=''
    glob_average_perem_1=''
    res_bias_check=''
    data_bias=''
    for i in range(num_conv):
        Y = Y + "Y" + str(i + 1) + ","
        w = w + "w"+str(i+1)+"1,w"+str(i+1)+"2,w"+str(i+1)+"3,"
        p = p + "p" + str(i) + "_1,p" + str(i) + "_2,p" + str(i) + "_3,"
        res_out = res_out + "res_out_" +str(i+1) + ","
        res = res + "res"+ str(i+1) + ","
        res_old = res_old + "res_old_" + str(i+1) + ","
        glob_average_perem = glob_average_perem + "glob_average_perem_" + str(i+1) + ","
        glob_average_perem_1 = glob_average_perem_1 + "glob_average_perem_" + str(i + 1) + "_1,"
        res_bias_check = res_bias_check + "res_bias_check_" + str(i+1) + ","
        data_bias = data_bias + "data_bias_" + str(i+1) + ","

    f.write("module conv_TOP(clk,conv_en,STOP,memstartp,memstartw,memstartzap,read_addressp,write_addressp,read_addresstp,write_addresstp,read_addressw,we,re_wb,re,we_t,re_t,qp,qtp,qw,dp,dtp,prov,matrix,matrix2,i_to_prov,lvl,slvl,mem,")
    f.write(Y)
    f.write(w)
    f.write(p)
    f.write("go,up_perm,down_perm,num,filt,bias,glob_average_en,step,stride,depthwise,onexone,q_bias,read_addressb,memstartb,stride_plus_prov);\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("parameter SIZE_"+str(i+1)+"=0;\n")
    f.write("parameter SIZE_address_pix=13;\n")
    f.write("parameter SIZE_address_pix_t=12;\n")
    f.write("parameter SIZE_address_wei=13;\n")
    f.write("parameter SIZE_weights=0;\n")
    f.write("parameter SIZE_bias=0;\n")
    f.write("\n")
    f.write("input clk,conv_en,glob_average_en;\n")
    f.write("input [1:0] prov;\n")
    f.write("input ["+str(bit_matrix-1)+":0] matrix;\n")
    f.write("input ["+str(bit_matrix_2-1)+":0] matrix2;\n")
    f.write("input [SIZE_address_pix-1:0] memstartp;\n")
    f.write("input [SIZE_address_wei-1:0] memstartw;\n")
    f.write("input [SIZE_address_pix-1:0] memstartzap;\n")
    f.write("input [10:0]				 memstartb;\n")
    f.write("input ["+str(bit_max_conv_input_size-1)+":0] lvl;\n")
    f.write("input [8:0] slvl;\n")
    f.write("output reg [SIZE_address_pix-1:0] read_addressp;\n")
    f.write("output reg [SIZE_address_pix_t-1:0] read_addresstp;\n")
    f.write("output reg [SIZE_address_wei-1:0] read_addressw;\n")
    f.write("output reg [10:0]				  read_addressb;\n")
    f.write("output reg [SIZE_address_pix-1:0] write_addressp;\n")
    f.write("output reg [SIZE_address_pix_t-1:0] write_addresstp;\n")
    f.write("output reg we,re,re_wb;\n")
    f.write("output reg we_t,re_t;\n")
    f.write("input signed [SIZE_"+str(num_conv)+"-1:0] qp;\n")
    f.write("input signed [32*"+str(num_conv)+"-1:0] qtp;\n")
    f.write("input signed [SIZE_weights*9-1:0] qw;\n")
    f.write("input signed [SIZE_bias-1:0] q_bias;\n")
    f.write("output signed [SIZE_"+str(num_conv)+"-1:0] dp;\n")
    f.write("output signed [32*"+str(num_conv)+"-1:0] dtp;\n")
    f.write("output reg STOP;\n")
    f.write("output reg ["+str(bit_razmer_2-1)+":0] i_to_prov;\n")
    f.write("input signed [32-1:0] "+Y[:-1]+";\n")
    f.write("output reg signed [SIZE_weights-1:0] "+w[:-1]+";\n")
    f.write("output reg signed [SIZE_1-1:0] "+p[:-1]+";\n")
    f.write("output reg go;\n")
    f.write("output reg up_perm,down_perm;\n")
    f.write("input [2:0] num;\n")
    f.write("input ["+str(bit_max_conv_output_size-1)+":0] mem;\n")
    f.write("input ["+str(bit_max_conv_input_size-1)+":0] filt;\n")
    f.write("input bias;\n")
    f.write("input ["+str(bit_steps_count-1)+":0] step;\n")
    f.write("input [1:0] stride;\n")
    f.write("output reg [SIZE_address_pix-1:0] stride_plus_prov;\n")
    f.write("\n")
    f.write("input depthwise,onexone;\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("reg signed [SIZE_weights-1:0] w" + str(i + 1) + "1_pre,w" + str(i + 1) + "2_pre,w" + str(i + 1) + "3_pre,w" + str(i + 1) + "4_pre,w" + str(i + 1) + "5_pre,w" + str(i + 1) + "6_pre,w" + str(i + 1) + "7_pre,w" + str(i + 1) + "8_pre,w" + str(i + 1) + "9_pre;\n")
    f.write("reg signed [SIZE_1-1:0]")
    for i in range(int(num_conv/4)):
        f.write("p" + str(0+8*i) + "_pre,p" + str(1+8*i) + "_pre,p" + str(2+8*i) + "_pre,p" + str(3+8*i) + "_pre,p" + str(4+8*i) + "_pre,p" + str(5+8*i) + "_pre,p" + str(6+8*i) + "_pre,p" + str(7+8*i) + "_pre")
        if ((i+1)==(int(num_conv/4))): f.write(";")
        else: f.write(",")
    f.write("\n")
    f.write("reg signed [SIZE_1-1:0] "+res_out[:-1]+";\n")
    f.write("reg signed [32-1:0] "+res[:-1]+";\n")
    f.write("reg signed [32-1:0] "+res_old[:-1]+";\n")
    f.write("reg signed [21:0] "+glob_average_perem[:-1]+";\n")
    f.write("wire signed [SIZE_1-1:0] "+glob_average_perem_1[:-1]+";\n")
    f.write("\n")
    f.write("reg signed [SIZE_1-1:0]")
    for i in range(num_conv):
        f.write("buff" + str(i) + "_0 [2:0]")
        if (i != (num_conv-1)): f.write(", ")
        else: f.write(";\n")
    f.write("reg signed [SIZE_1-1:0]")
    for i in range(num_conv):
        f.write("buff" + str(i) + "_1 [2:0]")
        if (i != (num_conv-1)): f.write(", ")
        else: f.write(";\n")
    f.write("reg signed [SIZE_1-1:0]")
    for i in range(num_conv):
        f.write("buff" + str(i) + "_2 [2:0]")
        if (i != (num_conv-1)): f.write(", ")
        else: f.write(";\n")
    f.write("\n")
    f.write("reg [4:0] marker;\n")
    f.write("reg zagryzka_weight;\n")
    f.write("reg [15:0] i;\n")
    f.write("reg [15:0] i_onexone,i_onexone_1;\n")
    f.write("wire [15:0] i_onexone_plus1;\n")
    f.write("assign i_onexone_plus1 = i_onexone + 1'b1;\n")
    f.write("reg [SIZE_address_pix-1:0] stride_plus,next_number,next_number_prov;\n")
    f.write("\n")
    f.write("reg signed [19-1:0] "+res_bias_check[:-1]+";\n")
    f.write("\n")
    f.write("reg signed [SIZE_bias-1:0] " + data_bias[:-1]+";\n")
    f.write("\n")
    f.write("initial zagryzka_weight=0;\n")
    f.write("initial marker=0;\n")
    f.write("\n")
    f.write("wire [15:0] line_stride;\n")
    f.write("\n")
    f.write("assign line_stride=matrix>>(stride-1);\n")
    f.write("\n")
    f.write("always @(posedge clk)\n")
    f.write("begin\n")
    f.write("if (conv_en==1)\n")
    f.write("	begin\n")
    f.write("		if (zagryzka_weight==0)\n")
    f.write("		begin\n")
    f.write("		   next_number = matrix;\n")
    f.write("		   next_number_prov = matrix;\n")
    f.write("		   if ((step!=3)&&(step!=12)&&(step!=24)&&(step!=36)&&(step!=72)) stride_plus=0;\n")
    f.write("		   else stride_plus=matrix;\n")
    f.write("		   if ((step!=3)&&(step!=12)&&(step!=24)&&(step!=36)&&(step!=72)) stride_plus_prov=0;\n")
    f.write("		   else stride_plus_prov=matrix;\n")
    f.write("		   case (marker)\n")

    for i in range(num_conv+2):
        f.write("				"+str(i)+": begin\n")
        if (i==0): f.write("				        re_wb=1;\n")
        if (i < num_conv):
            f.write("				        read_addressw=memstartw+" + str(i) + "*((depthwise)?1:((onexone)?((mem+1)>>3):(filt+1)));\n")
            f.write("				        read_addressb=memstartb+" + str(i) + ";\n")
        if ((i<num_conv+2)&(i>=2)):
            for j in range(9):
                f.write("				        w"+str(i-1)+str(j+1)+"_pre=qw[SIZE_weights*"+str(j+1)+"-1:")
                if (j==0): f.write("0")
                else: f.write("SIZE_weights*"+str(j))
                f.write("]; \n")
            f.write("\n")
            f.write("				        data_bias_" + str(i-1) + " = q_bias;\n")
        if (i == num_conv + 1): f.write("				        zagryzka_weight=1; re_wb=0; marker=-1;\n")
        f.write("				end\n")
    f.write("				default: \n")
    f.write("					begin\n")
    f.write("						read_addressw=0;\n")
    f.write("						read_addressb=0;\n")
    f.write("						re_wb=0;\n")
    f.write("						$display(\"Check zagryzka_weight\");\n")
    f.write("					end\n")
    f.write("		endcase\n")
    f.write("		marker=marker+1;\n")
    f.write("		end\n")
    f.write("		else\n")
    f.write("		begin\n")
    f.write("			re=1;\n")
    f.write("			case (marker)\n")
    f.write("				0: begin	\n")
    f.write("								re_t=0;\n")
    f.write("								if ((stride==2)&&(i==next_number))\n")
    f.write("									begin\n")
    f.write("										stride_plus=stride_plus+matrix;\n")
    f.write("										next_number = matrix+next_number;\n")
    f.write("									end\n")
    f.write("								if (onexone) read_addressp = memstartp+(matrix*matrix)*(3*i_onexone_1+marker)+i_onexone-1;\n")
    f.write("								else read_addressp=i+memstartp+stride_plus;\n")
    f.write("\n")
    f.write("								if (onexone)\n")
    f.write("									begin\n")
    for i in range(num_conv):
        f.write("										p" + str(i) + "_1=p6_pre;\n")
        f.write("										p" + str(i) + "_2=p7_pre;\n")
        f.write("										p" + str(i) + "_3=0;\n")
    f.write("									end\n")
    f.write("								else\n")
    f.write("									begin\n")
    f.write("										if (depthwise)\n")
    f.write("											begin\n")
    for i in range(num_conv):
        f.write("												buff" + str(i) + "_2[2]=qp[SIZE_" + str(num_conv-i) + "-1:")
        if (num_conv==(i+1)): f.write("0")
        else: f.write("SIZE_"+ str(num_conv-i-1))
        f.write("];\n")
    f.write("											end\n")
    f.write("										else\n")
    f.write("											begin\n")
    f.write("												if (((i+stride_plus-1)<matrix2-matrix)||(onexone))\n")
    f.write("													begin\n")

    lvl=''
    for i in range(len(bin(num_conv))-3):
        lvl = ",lvl["+str(i)+"]" + lvl
    for i in range(num_conv):
        one_size="SIZE_"+str(num_conv-i)
        if ((num_conv-i-1)==0): two_size="0"
        else: two_size="SIZE_"+str(num_conv-i-1)
        if (num_conv>1):
            if (i==0):
                f.write("													    if")
            else:
                f.write("													    else if")
            f.write(" ({"+lvl[1:]+"}=="+str(len(bin(num_conv))-3)+"'d"+str(i)+") \n")
            f.write("															begin\n")
            for i in range(num_conv):
                f.write("																buff" + str(i) + "_2[2]=qp["+one_size+"-1:"+two_size+"];\n")
            f.write("															end\n")
        else:
            f.write("															begin\n")
            for i in range(num_conv):
                f.write("																buff" + str(i) + "2[2]=qp[SIZE_1-1:0];\n")
            f.write("															end\n")
    f.write("													end\n")
    f.write("												else\n")
    f.write("													begin\n")

    for i in range(num_conv):
        f.write("														buff" + str(i) + "_2[2]=0;\n")
    f.write("													end\n")
    f.write("											end\n")
    for i in range(num_conv):
        f.write("											p" + str(i) + "_1=buff" + str(i) + "_2[0];\n")
        f.write("											p" + str(i) + "_2=buff" + str(i) + "_2[1];\n")
        f.write("											p" + str(i) + "_3=buff" + str(i) + "_2[2];\n")
        f.write("\n")
    f.write("									end\n")
    f.write("\n")

    for i in range(num_conv):
        f.write("								w" + str(i+1) + "1=(onexone)?w" + str(i+1) + "3_pre:w" + str(i+1) + "3_pre;\n")
        f.write("								w" + str(i+1) + "2=(onexone)?w" + str(i+1) + "2_pre:w" + str(i+1) + "2_pre;\n")
        f.write("								w" + str(i+1) + "3=(onexone)?w" + str(i+1) + "1_pre:w" + str(i+1) + "1_pre;\n")
    f.write("								up_perm=0;\n")
    f.write("								if (onexone) down_perm=0; else down_perm=1;\n")
    for i in range(num_conv):
        f.write("								res" + str(i+1) + "=Y" + str(i+1) + ";\n")
    f.write("					end\n")
    f.write("				1: begin\n")
    f.write("								if (onexone) read_addressp = memstartp+(matrix*matrix)*(3*i_onexone_1+marker)+i_onexone-1;\n")
    f.write("								else	if ((i+stride_plus)>=matrix-1)	read_addressp=i-matrix+memstartp+stride_plus;\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("								res" + str(i+1) + "=res" + str(i+1) + "+Y" + str(i+1) + ";\n")
    f.write("								if ((i>=2)&&(((stride==2)&&((((step==3)||(step==12)||(step==24)||(step==36)||(step==72))&&(i[0]==1))||(((step!=3)&&(step!=12)&&(step!=24)&&(step!=36)&&(step!=72))&&(i[0]==0))))||(stride==1))) \n")
    f.write("									begin\n")
    for i in range(num_conv):
        f.write("										res_old_" + str(i+1) + "=qtp[32*" + str(num_conv-i) + "-1:32*")
        if (num_conv==(i+1)): f.write("0")
        else: f.write(str(num_conv-i-1))
        f.write("];\n")
    f.write("									end\n")
    f.write("								go=0;\n")
    f.write("								i_to_prov=i_to_prov+1'b1;\n")
    f.write("								if ((stride==2)&&(i_to_prov==next_number_prov)) \n")
    f.write("									begin\n")
    f.write("										stride_plus_prov=stride_plus_prov+matrix;\n")
    f.write("										next_number_prov = matrix+next_number_prov;\n")
    f.write("									end\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("								buff" + str(i) + "_2[0]=buff" + str(i) + "_2[1];\n")
        f.write("								buff" + str(i) + "_1[0]=buff" + str(i) + "_1[1];\n")
        f.write("								buff" + str(i) + "_0[0]=buff" + str(i) + "_0[1];\n")
        f.write("								buff" + str(i) + "_2[1]=buff" + str(i) + "_2[2];\n")
        f.write("								buff" + str(i) + "_1[1]=buff" + str(i) + "_1[2];\n")
        f.write("								buff" + str(i) + "_0[1]=buff" + str(i) + "_0[2];\n")
        f.write("\n")
    f.write("					end\n")
    f.write("				2: begin\n")
    f.write("							if (onexone) read_addressp = memstartp+(matrix*matrix)*(3*i_onexone_1+marker)+i_onexone-1;\n")
    f.write("							else	if ((i+stride_plus)<matrix2-matrix) read_addressp=i+matrix+memstartp+stride_plus;\n")
    f.write("\n")
    f.write("							if (onexone)\n")
    f.write("								begin\n")
    for i in range(num_conv):
        f.write("									p" + str(i) + "_pre = qp[SIZE_" + str(num_conv-i) + "-1:")
        if (num_conv==(i+1)): f.write("0")
        else: f.write("SIZE_" + str(num_conv-i-1))
        f.write("];\n")
    for i in range(num_conv):
        f.write("									p" + str(i) + "_1=p0_pre;\n")
        f.write("									p" + str(i) + "_2=p1_pre;\n")
        f.write("									p" + str(i) + "_3=p2_pre;\n")
        f.write("\n")
    f.write("								end\n")
    f.write("							else\n")
    f.write("								begin\n")
    f.write("									if (depthwise)\n")
    f.write("										begin\n")
    for i in range(num_conv):
        f.write("											buff" + str(i) + "_1[2]=qp[SIZE_" + str(num_conv-i) + "-1:")
        if (num_conv==(i+1)): f.write("0")
        else: f.write("SIZE_" + str(num_conv-i-1))
        f.write("];\n")
    f.write("										end\n")
    f.write("									else\n")
    f.write("										begin\n")

    lvl=''
    for i in range(len(bin(num_conv))-3):
        lvl = ",lvl["+str(i)+"]" + lvl
    for i in range(num_conv):
        one_size="SIZE_"+str(num_conv-i)
        if ((num_conv-i-1)==0): two_size="0"
        else: two_size="SIZE_"+str(num_conv-i-1)
        if (num_conv>1):
            if (i==0):
                f.write("											if")
            else:
                f.write("											else if")
            f.write(" ({"+lvl[1:]+"}=="+str(len(bin(num_conv))-3)+"'d"+str(i)+") \n")
            f.write("												begin\n")
            for i in range(num_conv):
                f.write("													buff" + str(i) + "_1[2]=qp["+one_size+"-1:"+two_size+"];\n")
            f.write("												end\n")
        else:
            f.write("												begin\n")
            for i in range(num_conv):
                f.write("													buff" + str(i) + "1[2]=qp[SIZE_1-1:0];\n")
            f.write("												end\n")
    f.write("										end\n")
    for i in range(num_conv):
        f.write("										p" + str(i) + "_1=buff" + str(i) + "_1[0];\n")
        f.write("										p" + str(i) + "_2=buff" + str(i) + "_1[1];\n")
        f.write("										p" + str(i) + "_3=buff" + str(i) + "_1[2];\n")
        f.write("\n")
    f.write("								end\n")
    for i in range(num_conv):
        f.write("								w" + str(i+1) + "1=(onexone)?w" + str(i+1) + "9_pre:w" + str(i+1) + "6_pre;\n")
        f.write("								w" + str(i+1) + "2=(onexone)?w" + str(i+1) + "8_pre:w" + str(i+1) + "5_pre;\n")
        f.write("								w" + str(i+1) + "3=(onexone)?w" + str(i+1) + "7_pre:w" + str(i+1) + "4_pre;\n")
        f.write("\n")
    f.write("								go=1;\n")
    f.write("								up_perm=0;\n")
    f.write("								down_perm=0;\n")
    f.write("								if ((i>=2)&&(((stride==2)&&((((step==3)||(step==12)||(step==24)||(step==36)||(step==72))&&(i[0]==1))||(((step!=3)&&(step!=12)&&(step!=24)&&(step!=36)&&(step!=72))&&(i[0]==0))))||(stride==1)))\n")
    f.write("								begin\n")
    f.write("								if (onexone) write_addresstp=i_onexone-2;\n")
    f.write("								else write_addresstp=(i>>(stride-1))-1;\n")
    f.write("								if (glob_average_en)  write_addressp=memstartzap;\n")
    f.write("								else\n")
    f.write("									begin\n")
    f.write("										if (onexone)	write_addressp=memstartzap+i_onexone-2;\n")
    f.write("										else			write_addressp=memstartzap+((i-2)>>(stride-1));\n")
    f.write("									end\n")
    f.write("\n")
    f.write("								if (((onexone && (i_onexone_1 == 0)) || !onexone)&&(!bias)) we_t=1;\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("								res" + str(i+1) + "=res" + str(i+1) + "+Y" + str(i+1) + ";\n")
    f.write("\n")
    f.write("								if ((lvl!=0)&&(!depthwise))\n")
    f.write("									begin\n")
    for i in range(num_conv):
        f.write("										res" + str(i+1) + "=res" + str(i+1) + "+res_old_" + str(i+1) + ";\n")
    f.write("									end\n")
    f.write("								if (bias)\n")
    f.write("									begin\n")
    for i in range(num_conv):
        f.write("										res" + str(i+1) + "=res" + str(i+1) + "+(data_bias_" + str(i+1) + "<<"+str(sizeI+1)+");\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("										if (res" + str(i+1) + "<0) res" + str(i+1) + "=0;  //RELU\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("										res_bias_check_" + str(i+1) + "=res" + str(i+1) + "["+ str(sizeI+sizeW+2) +"-1-2:SIZE_1-2];\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("										if (res_bias_check_" + str(i+1) + ">(2**(SIZE_1-1))-1) res_out_" + str(i+1) + "=(2**(SIZE_1-1))-1;\n")
        f.write("										else res_out_" + str(i+1) + "=res" + str(i+1) + "[SIZE_1+SIZE_1-2-2:SIZE_1-2];\n")
    f.write("\n")
    f.write("										if ((glob_average_en)&&(i_onexone_1 == 0))\n")
    f.write("											begin\n")
    for i in range(num_conv):
        f.write("												glob_average_perem_" + str(i+1) + " = glob_average_perem_" + str(i+1) + " + res_out_" + str(i+1) + ";\n")
    f.write("											end\n")
    f.write("										if ((onexone && (i_onexone_1 == 0)) || !onexone) we=1;\n")
    f.write("									end\n")
    f.write("								end\n")
    f.write("					end\n")
    f.write("				3: begin\n")
    f.write("								re_t=1;\n")
    f.write("								if (onexone) read_addresstp=i_onexone-1;\n")
    f.write("								else read_addresstp=(i>>(stride-1))-1;\n")
    f.write("\n")
    f.write("								if (onexone)\n")
    f.write("									begin\n")
    if (num_conv<8):
        for i in range(num_conv):
            f.write("										p" + str(num_conv+i) +  "_pre = qp[SIZE_" + str(num_conv-i) +  "-1:")
            if (num_conv==(i+1)): f.write("0")
            else: f.write("SIZE_" + str(num_conv-i-1))
            f.write("];\n")
        f.write("\n")
    for i in range(num_conv):
        f.write("										p" + str(i) + "_1=p3_pre;\n")
        f.write("										p" + str(i) + "_2=p4_pre;\n")
        f.write("										p" + str(i) + "_3=p5_pre;\n")
        f.write("\n")
    f.write("									end\n")
    f.write("								else\n")
    f.write("									begin\n")
    f.write("										if (depthwise)\n")
    f.write("											begin\n")
    for i in range(num_conv):
        f.write("												buff" + str(i) + "_0[2]=qp[SIZE_" + str(num_conv-i) +  "-1:")
        if (num_conv==(i+1)): f.write("0")
        else: f.write("SIZE_" + str(num_conv-i-1))
        f.write("];\n")
    f.write("											end\n")
    f.write("										else\n")
    f.write("											begin\n")
    f.write("												if ((i+stride_plus)>=matrix-1)\n")
    f.write("												begin\n")

    lvl=''
    for i in range(len(bin(num_conv))-3):
        lvl = ",lvl["+str(i)+"]" + lvl
    for i in range(num_conv):
        one_size="SIZE_"+str(num_conv-i)
        if ((num_conv-i-1)==0): two_size="0"
        else: two_size="SIZE_"+str(num_conv-i-1)
        if (num_conv>1):
            if (i==0):
                f.write("													if")
            else:
                f.write("													else if")
            f.write(" ({"+lvl[1:]+"}=="+str(len(bin(num_conv))-3)+"'d"+str(i)+") \n")
            f.write("														begin\n")
            for i in range(num_conv):
                f.write("															buff" + str(i) + "_0[2]=qp["+one_size+"-1:"+two_size+"];\n")
            f.write("														end\n")
        else:
            f.write("														begin\n")
            for i in range(num_conv):
                f.write("															buff" + str(i) + "0[2]=qp[SIZE_1-1:0];\n")
            f.write("														end\n")
    f.write("												end\n")
    f.write("												else\n")
    f.write("													begin\n")
    for i in range(num_conv):
        f.write("														buff" + str(i) + "_0[2]=0;\n")
    f.write("													end\n")
    f.write("											end\n")
    for i in range(num_conv):
        f.write("										p" + str(i) + "_1=buff" + str(i) + "_0[0];\n")
        f.write("										p" + str(i) + "_2=buff" + str(i) + "_0[1];\n")
        f.write("										p" + str(i) + "_3=buff" + str(i) + "_0[2];\n")
        f.write("\n")
    f.write("									end\n")
    for i in range(num_conv):
        f.write("								w" + str(i+1) + "1=(onexone)?w" + str(i+1) + "6_pre:w" + str(i+1) + "9_pre;\n")
        f.write("								w" + str(i+1) + "2=(onexone)?w" + str(i+1) + "5_pre:w" + str(i+1) + "8_pre;\n")
        f.write("								w" + str(i+1) + "3=(onexone)?w" + str(i+1) + "4_pre:w" + str(i+1) + "7_pre;\n")
        f.write("\n")
    f.write("								if (onexone) up_perm=0; else up_perm=1;\n")
    f.write("								down_perm=0;\n")
    f.write("								we_t=0;\n")
    f.write("								we=0;\n")
    f.write("					end		\n")
    f.write("			default: $display(\"Check case conv_TOP\");\n")
    f.write("			endcase\n")
    f.write("\n")
    f.write("			if (marker!=3) marker=marker+1;\n")
    f.write("			else begin \n")
    f.write("					marker=0; \n")
    f.write("					if (((i<matrix*line_stride+1)&&(!onexone))||((onexone)&&(i_onexone_plus1<(matrix*line_stride)+2)))\n")
    f.write("						begin\n")
    f.write("							i=i+1; \n")
    f.write("							if (onexone)\n")
    f.write("								begin\n")
    f.write("									if (i_onexone_1 == 2>>2)\n")
    f.write("										begin\n")
    f.write("											i_onexone = i_onexone + 1;\n")
    f.write("											i_onexone_1 = 0;\n")
    f.write("										end\n")
    f.write("									else	i_onexone_1 = i_onexone_1 + 1;\n")
    f.write("								end\n")
    f.write("						end\n")
    f.write("					else STOP=1; \n")
    f.write("				  end\n")
    f.write("		end\n")
    f.write("	end\n")
    f.write("else \n")
    f.write("	begin\n")
    f.write("		i=0;\n")
    f.write("		i_to_prov=-2;\n")
    f.write("		stride_plus=0;\n")
    f.write("		next_number=matrix;\n")
    f.write("		zagryzka_weight=0;\n")
    f.write("		STOP=0;\n")
    f.write("		re=0;\n")
    f.write("		re_t=0;\n")
    f.write("		go=0;\n")
    f.write("		marker=0;\n")
    for i in range(num_conv):
        f.write("		glob_average_perem_"+str(i+1)+"=0;\n")
    f.write("		i_onexone = 0;\n")
    f.write("		i_onexone_1 = 0;\n")
    f.write("		read_addressw=0;\n")
    f.write("		read_addressb=0;\n")
    f.write("		re_wb=0;\n")
    f.write("	end\n")
    f.write("end\n")
    for i in range(num_conv):
        f.write("assign glob_average_perem_" + str(i+1) + "_1=glob_average_perem_" + str(i+1) + ">>4;\n")
    f.write("assign dp={")
    for i in range(num_conv):
        f.write("(glob_average_en?glob_average_perem_" + str(i+1) + "_1:res_out_" + str(i+1) + ")")
        if ((i+1)!=num_conv): f.write(",")
        f.write("\n")
    f.write("};\n")
    f.write("assign dtp={" + str(res[:-1]) + "};\n")
    f.write("endmodule\n")

    f.close()

def dense(directory, in_dense_razmer, out_dense_razmer, num_conv, sizeI, sizeW):
    file = open(directory + "dense.v", 'w')

    bit_in = len(bin(in_dense_razmer)) - 2
    bit_out = len(bin(out_dense_razmer)) - 2
    Y=''
    w=''
    p=''
    Ypl=''
    Y_use=''
    Y_use_pl=''
    for i in range(num_conv):
        Y=Y+" Y"+str(i+1)+","
        Y_use=Y_use+" Y"+str(i+1)+"_use,"
        Y_use_pl = Y_use_pl + " Y" + str(i + 1) + "_use+"
        Ypl = Ypl + " (Y" + str(i + 1) + "_use?Y" + str(i + 1) + ":0)+"
        w=w+" w"+str(i+1)+"1, w"+str(i+1)+"2, w"+str(i+1)+"3,"
        p=p+" p"+str(i+1)+"1, p"+str(i+1)+"2, p"+str(i+1)+"3,"

    file.write("module dense(clk, dense_en, STOP, in, out, we, re_p, re_w, read_addressp, read_addressw, write_addressp, memstartp, memstartzap, qp, qw, res,"+Y+w+p+" go, nozero);\n\n")
    file.write("parameter num_conv=0;\n")
    file.write("\n")
    for i in range(num_conv):
        file.write("parameter SIZE_"+str(i+1)+"=0;\n")
    file.write("parameter SIZE_address_pix=0;\n")
    file.write("parameter SIZE_address_wei=0;\n")
    file.write("parameter SIZE_weights=0;\n")
    file.write("\n")
    file.write("input clk,dense_en;\n")
    file.write("output reg STOP;\n")
    file.write("input ["+str(bit_in-1)+":0] in;\n")
    file.write("input ["+str(bit_out-1)+":0] out;\n")
    file.write("output reg we,re_p,re_w;\n")
    file.write("output reg [SIZE_address_pix-1:0] read_addressp;\n")
    file.write("output reg [SIZE_address_wei-1:0] read_addressw;\n")
    file.write("output reg [SIZE_address_pix-1:0] write_addressp;\n")
    file.write("input [SIZE_address_pix-1:0] memstartp,memstartzap;\n")
    file.write("input signed [SIZE_"+str(num_conv)+"-1:0] qp;\n")
    file.write("input signed [SIZE_weights*9-1:0] qw;\n")
    file.write("output reg signed [SIZE_"+str(num_conv)+"-1:0] res;\n")
    file.write("input signed [32-1:0]"+Y[:-1]+";\n")
    file.write("output reg signed [SIZE_weights - 1:0]"+w[:-1]+";\n")
    file.write("output reg signed [SIZE_1-1:0]"+p[:-1]+";\n")
    file.write("output reg go;\n")
    file.write("input nozero;\n")
    file.write("\n")
    for i in range(num_conv):
        file.write("reg signed[SIZE_weights - 1:0] w"+str(i+1)+"1_pre, w"+str(i+1)+"2_pre, w"+str(i+1)+"3_pre, w"+str(i+1)+"4_pre, w"+str(i+1)+"5_pre, w"+str(i+1)+"6_pre, w"+str(i+1)+"7_pre, w"+str(i+1)+"8_pre, w"+str(i+1)+"9_pre;\n")
    file.write("\n")
    for i in range(num_conv):
        file.write("reg signed[SIZE_1 - 1:0] p"+str(i+1)+"1_pre, p"+str(i+1)+"2_pre, p"+str(i+1)+"3_pre, p"+str(i+1)+"4_pre, p"+str(i+1)+"5_pre, p"+str(i+1)+"6_pre, p"+str(i+1)+"7_pre, p"+str(i+1)+"8_pre, p"+str(i+1)+"9_pre;\n")
    file.write("reg [3:0] marker;\n")
    file.write("reg [6:0] lvl;\n")
    file.write("reg [8:0] i;\n")
    file.write("reg [8:0] j;\n")

    bit_sh=len(bin(num_conv)) - 4
    if (bit_sh>0): sh="["+str(bit_sh)+":0]"
    else: sh=''

    file.write("reg "+sh+" sh;\n")
    file.write("reg signed [32-1:0] dp;\n") ###[(SIZE_2)*"+str(num_conv)+"-1:0]
    file.write("reg signed [SIZE_1-1:0] dp_shift;\n")
    file.write("reg signed [19-1:0]dp_check;\n\n")
    file.write("always @(posedge clk)\n")
    file.write("begin\n")
    file.write("    if (dense_en==1)\n")
    file.write("    begin\n")
    file.write("        re_p=1;\n")
    file.write("        case (marker)\n")        

    k1=1
    k2=1
    k3=1
    k4=1
    k7=1
    k8=1
    k9=1
    k10=1

    i=2
    STOP=0
    while (STOP==0):

        file.write(str(i)+":begin\n")
        file.write("    if (i>(in>>"+str(len(bin(num_conv))-3)+")+1) begin\n")
        file.write("       ")
        for j in range(num_conv):
            file.write(" p"+str(k1)+str(k2)+"_pre = 0;")
            if (k2==9):
                k2=1
                k1+=1
            else: k2+=1

        file.write("\n    end\n")
        file.write("    else begin\n")
        file.write("       ")
        for j in range(num_conv):
            one="SIZE_"+str(num_conv-j)
            if (num_conv-j-1==0): two="0"
            else: two = "SIZE_"+str(num_conv - j - 1)
            file.write(" p"+str(k3)+str(k4)+"_pre = qp["+one+" - 1:"+two+"];")
            if (k4==9):
                k4=1
                k3+=1
            else: k4+=1
        file.write("\n    end\n")

        file.write("    ")
        if (((i>=2)|((i<2)&((i+num_conv)<=num_conv)))&(i<(num_conv+2))):
            k6=9
            for k5 in range(9):
                if (i<2): m=(num_conv*1+1)
                else: m=0
                file.write("w"+str(i-1+m)+str(k5+1)+"_pre=qw[SIZE_weights*"+str(k6)+"-1:SIZE_weights*")
                if ((k6-1)==0): file.write("0]; ")
                else: file.write(str(k6-1)+"]; ")
                k6-=1
        file.write("\n")

        if (i<num_conv): file.write("    read_addressw = lvl*29 + " + str(i) + " + j*" + str(num_conv) + ";\n")

        if (i==0):
            file.write("    we=0;\n")
            file.write("    re_w=1;\n")
        if (i==1):
            STOP=1
        if ((i==2)|(i==5)|(i==8)): file.write("    go=0;\n")
        if (i==num_conv+1): file.write("    re_w=0;\n")
        if ((i==3)|(i==6)|(i==0)):
            if ((i==3)|(i==0)): file.write("    if (i!="+str(i)+") ")
            else: file.write("    ")
            file.write("dp=")
            for j in range(num_conv):
                file.write("Y"+str(j+1)+"+")
            file.write("dp;\n")
        if ((i==1)|(i==4)|(i==7)):
            file.write("    ")
            if (i==1): file.write("if (i!=1) ")
            file.write("go=1;\n")
            for j in range(num_conv):
                file.write("    ")
                for k in range(3):
                    file.write("p" + str(j + 1) + str(k + 1) + "=")
                    file.write("p" + str(k7) + str(k8) + "_pre; ")
                    if (k8 == 9):
                        k8 = 1
                        k7 += 1
                    else:
                        k8 += 1
                file.write("\n")
            file.write("\n")

            for j in range(num_conv):
                file.write("    ")
                for k in range(3):
                    file.write("w" + str(j + 1) + str(k + 1) + "=")
                    file.write("w" + str(k9) + str(k10) + "_pre; ")
                    if (k10 == 9):
                        k10 = 1
                        k9 += 1
                    else:
                        k10 += 1
                file.write("\n")
            file.write("\n")

        if (i==num_conv): file.write("    j=j+1;\n")
        file.write("    end\n")

        if (i!=8): i=i+1
        else: i=0

    file.write("            default: $display(\"Check case dense\");\n")
    file.write("        endcase\n\n")
    file.write("        read_addressp=memstartp+i;\n\n")
    file.write("        if (marker!=8) marker=marker+1; else marker=0;\n")
    file.write("        i=i+1;\n")
    file.write("        if ((i>(in>>"+str(len(bin(num_conv))-3)+")+4)&&(marker==4))\n")
    file.write("            begin\n")
    file.write("        	    write_addressp=memstartzap+(lvl>>(num_conv>>1));\n")
    file.write("                dp_check=dp["+str(sizeI+sizeW+2)+"-1-2:SIZE_1-2];\n")
    file.write("                if ((dp_shift<0)&&(nozero==0)) dp_shift=0;\n")
    file.write("		        if (dp_check>2**(SIZE_1-1)-1) dp_shift=2**(SIZE_1-1)-1;\n")
    file.write("                else dp_shift=dp_check;\n")
    for i in range(num_conv):
        file.write("                if (sh == "+str(i)+") begin")
        if (i==0): file.write(" res=0;")
        file.write(" res[SIZE_"+str(num_conv-i)+"-1:")
        if (num_conv-i-1==0): file.write("0")
        else: file.write("SIZE_"+str(num_conv-i-1))
        file.write("]=dp_shift; end\n")
    file.write("                lvl=lvl+1;\n")
    file.write("                i=0; \n")
    file.write("                j=0; \n")
    file.write("                dp=0; \n")
    file.write("                marker=0;\n")
    file.write("                sh=sh+1; if (sh==num_conv) sh=0; \n")
    file.write("		        if ((sh==0)||(lvl==out)) we=1;\n")
    file.write("                if (lvl==out) STOP=1;\n")
    file.write("    end\n")
    file.write("end\n")
    file.write("else\n")
    file.write("begin\n")
    file.write("    marker=0;\n")
    file.write("    i=0;\n")
    file.write("    j=0;\n")
    file.write("    sh=0;\n")
    file.write("    we=0;\n")
    file.write("    dp=0;\n")
    file.write("    res=0;\n")
    file.write("    re_p=0;\n")
    file.write("    re_w=0;\n")
    file.write("    STOP=0;\n")
    file.write("    lvl=0;\n")
    file.write("end\n")
    file.write("end\n")
    file.write("endmodule\n")

    file.close()

def RAM(directory, max_weights_per_layer, num_conv):
    f = open(directory + "RAM.v", 'w')

    f.write("module RAM(qp,qtp,qw,dp,dtp,dw,write_addressp,read_addressp,write_addresstp,read_addresstp,write_addressw,read_addressw,we_p,we_tp,we_w,re_p,re_tp,re_w,clk,clk_RAM_w,q_bias,d_bias,we_bias,re_bias,write_address_bias,read_address_bias);\n")
    f.write("parameter picture_size=0;	\n")
    for i in range(num_conv):
        f.write("parameter SIZE_"+str(i+1)+"=0;\n")
    f.write("parameter SIZE_address_pix=13;\n")
    f.write("parameter SIZE_address_pix_t=12;\n")
    f.write("parameter SIZE_address_wei=13;\n")
    f.write("parameter SIZE_address_image=16;\n")
    f.write("parameter SIZE_weights=0;\n")
    f.write("parameter SIZE_bias=0;\n")
    f.write("\n")
    f.write("output reg signed [SIZE_"+str(num_conv)+"-1:0] qp;       //read data\n")
    f.write("output reg signed [32*"+str(num_conv)+"-1:0] qtp;       //read data\n")
    f.write("output reg signed [SIZE_weights*9-1:0] qw;      //read weight\n")
    f.write("output reg signed [SIZE_bias-1:0] q_bias;\n")
    f.write("input signed [SIZE_1*"+str(num_conv)+"-1:0] dp;   //write data\n")
    f.write("input signed [32*"+str(num_conv)+"-1:0] dtp;   //write data\n")
    f.write("input signed [SIZE_weights*9-1:0] dw;   //write weight\n")
    f.write("input signed [SIZE_bias-1:0] d_bias;\n")
    f.write("input [SIZE_address_pix-1:0] write_addressp, read_addressp;\n")
    f.write("input [SIZE_address_pix_t-1:0] write_addresstp, read_addresstp;\n")
    f.write("input [SIZE_address_wei-1:0] write_addressw, read_addressw;\n")
    f.write("input [10:0] write_address_bias,read_address_bias;\n")
    f.write("input we_p;\n")
    f.write("input we_tp;\n")
    f.write("input we_w;\n")
    f.write("input we_bias;\n")
    f.write("input re_p;\n")
    f.write("input re_tp;\n")
    f.write("input re_w;\n")
    f.write("input re_bias;\n")
    f.write("input clk,clk_RAM_w;\n")
    f.write("\n")
    f.write("reg signed [SIZE_1*"+str(num_conv)+"-1:0] mem [0:128*128*"+str(int(4/num_conv))+"+4096*"+str(num_conv)+"-1];\n")
    f.write("reg signed [32*"+str(num_conv)+"-1:0] mem_t [0:4096-1];\n")
    f.write("reg signed [SIZE_weights*9-1:0] weight [0:4095]; \n")
    f.write("reg signed [SIZE_bias-1:0] mem_bias [0:256];\n")
    f.write("always @ (posedge clk) \n")
    f.write("    begin\n")
    f.write("      if (we_p)  mem[write_addressp] <= dp;\n")
    f.write("		if (we_tp) mem_t[write_addresstp] <= dtp;\n")
    f.write("    end\n")
    f.write("always @ (posedge clk_RAM_w)\n")
    f.write("	begin\n")
    f.write("		if (we_w) weight[write_addressw] <= dw;\n")
    f.write("		if (we_bias) mem_bias[write_address_bias] <= d_bias;\n")
    f.write("	end\n")
    f.write("always @ (posedge clk)\n")
    f.write("    begin\n")
    f.write("      if (re_p) qp <= mem[read_addressp];\n")
    f.write("		if (re_tp)qtp <= mem_t[read_addresstp];\n")
    f.write("      if (re_w) qw <= weight[read_addressw];\n")
    f.write("		if (re_bias) q_bias <= mem_bias[read_address_bias];\n")
    f.write("    end\n")
    f.write("\n")
    f.write("endmodule\n")

    f.close()

def RAMtoMEM(directory, max_address_value, steps_count, in_dense_razmer, conv_block_size, num_conv):
    f = open(directory + "RAMtoMEM.v", 'w')

    bit_max_address_value = len(bin(max_address_value)) - 2
    bit_weight_case = len(bin(conv_block_size*conv_block_size)) - 2
    bit_steps_count = len(bin(steps_count)) - 2
    bit_in_dense_razmer = len(bin(in_dense_razmer)) - 2

    f.write("module memorywork(clk_RAM_w,data,data_bias,address,we_w,re_weights,re_bias,nextstep,dw,addrw,step_out,GO,in_dense,load_weights,onexone,address_bias,d_bias,load_bias,we_bias,write_address_bias);\n")
    f.write("\n")
    f.write("parameter num_conv=0;\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("parameter SIZE_"+str(i+1)+"=0;\n")
    f.write("parameter SIZE_address_pix=0;\n")
    f.write("parameter SIZE_address_wei=0;\n")
    f.write("parameter SIZE_weights=0;\n")
    f.write("parameter SIZE_bias=0;\n")
    f.write("\n")
    f.write("input clk_RAM_w;\n")
    f.write("input signed [SIZE_weights-1:0] data;\n")
    f.write("input signed [SIZE_bias-1:0] data_bias;\n")
    f.write("output [23:0] address;\n")
    f.write("output reg we_w;\n")
    f.write("output re_weights,re_bias;\n")
    f.write("input nextstep;\n")
    f.write("output reg signed [SIZE_weights*9-1:0] dw;\n")
    f.write("output reg [SIZE_address_wei-1:0] addrw;\n")
    f.write("output ["+str(bit_steps_count-1)+":0] step_out;\n")
    f.write("input GO;\n")
    f.write("input ["+str(bit_in_dense_razmer-1)+":0] in_dense;\n")
    f.write("input load_weights,load_bias;\n")
    f.write("\n")
    f.write("output reg signed [SIZE_bias-1:0] d_bias;\n")
    f.write("output reg we_bias;\n")
    f.write("output reg [10:0] write_address_bias;\n")
    f.write("output [11:0] address_bias;\n")
    f.write("\n")
    f.write("input onexone; \n")
    f.write("\n")
    f.write("reg [SIZE_address_pix-1:0] addr;\n")
    f.write("wire ["+str(bit_max_address_value-1)+":0] firstaddr,lastaddr;\n")
    f.write("\n")
    f.write("wire [18:0] razn_addr;\n")
    f.write("assign razn_addr = lastaddr-firstaddr;\n")
    f.write("\n")
    f.write("reg ["+str(bit_steps_count-1)+":0] step;\n")
    f.write("reg ["+str(bit_steps_count-1)+":0] step_n;\n")
    f.write("reg ["+str(bit_weight_case-1)+":0] weight_case;\n")
    f.write("reg [SIZE_weights*9-1:0] buff;\n")
    f.write("reg ["+str(bit_max_address_value-1)+":0] i;\n")
    f.write("reg ["+str(bit_max_address_value-1)+":0] i_d;\n")
    f.write("reg ["+str(bit_max_address_value-1)+":0] i1;\n")
    f.write("addressRAM inst_1(.step(step_out),.re_weights(re_weights),.re_bias(re_bias),.firstaddr(firstaddr),.lastaddr(lastaddr));  \n")
    f.write("initial weight_case=0;\n")
    f.write("initial i=0;\n")
    f.write("initial i_d=0;\n")
    f.write("initial i1=0;\n")
    f.write("\n")
    f.write("always @(negedge clk_RAM_w)\n")
    f.write("	if (  (step_out==1)||(step_out==2)\n")
    f.write("		||(step_out==4)||(step_out==5)\n")
    f.write("		||(step_out==7)||(step_out==8)\n")
    f.write("		||(step_out==10)||(step_out==11)\n")
    f.write("		||(step_out==13)||(step_out==14)\n")
    f.write("		||(step_out==16)||(step_out==17)\n")
    f.write("		||(step_out==19)||(step_out==20)\n")
    f.write("		||(step_out==22)||(step_out==23)\n")
    f.write("		||(step_out==25)||(step_out==26)\n")
    f.write("		||(step_out==28)||(step_out==29)\n")
    f.write("		||(step_out==31)||(step_out==32)\n")
    f.write("		||(step_out==34)||(step_out==35)\n")
    f.write("		||(step_out==37)||(step_out==38)\n")
    f.write("		||(step_out==40)||(step_out==41)\n")
    f.write("		||(step_out==43)||(step_out==44)\n")
    f.write("		||(step_out==46)||(step_out==47)\n")
    f.write("		||(step_out==49)||(step_out==50)\n")
    f.write("		||(step_out==52)||(step_out==53)\n")
    f.write("		||(step_out==55)||(step_out==56)\n")
    f.write("		||(step_out==58)||(step_out==59)\n")
    f.write("		||(step_out==61)||(step_out==62)\n")
    f.write("		||(step_out==64)||(step_out==65)\n")
    f.write("		||(step_out==67)||(step_out==68)\n")
    f.write("		||(step_out==70)||(step_out==71)\n")
    f.write("		||(step_out==73)||(step_out==74)\n")
    f.write("		||(step_out==76)||(step_out==77)\n")
    f.write("		||(step_out==79)||(step_out==80)\n")
    f.write("		||(step_out==82)||(step_out==83)\n")
    f.write("		||(step_out==85)\n")
    f.write("		)\n")
    f.write("	begin\n")
    f.write("		if ((i<=razn_addr+1)&&(re_weights))  addr=i1;\n")
    f.write("		if ((i<=razn_addr+1)&&(re_bias))	addr=i;\n")
    f.write("	end\n")
    f.write("\n")
    f.write("always @(posedge clk_RAM_w or posedge GO)\n")
    f.write("	if (GO) step=1;\n")
    f.write("	else\n")
    f.write("    begin\n")
    f.write("			case (step_out)\n")
    f.write("				8'd1,8'd4,8'd7,8'd10,8'd13,8'd16,8'd19,8'd22,8'd25,8'd28,8'd31,8'd34,8'd37,8'd40,8'd43,8'd46,8'd49,8'd52,8'd55,8'd58,8'd61,8'd64,8'd67,8'd70,8'd73,8'd76,8'd79,8'd82,8'd85:\n")
    f.write("					begin\n")
    f.write("						if (i<=razn_addr+3)\n")
    f.write("                    begin\n")
    f.write("										we_w=0;\n")
    f.write("										addrw=addr;\n")
    f.write("										if (load_weights==1'b1) i=i+1; \n")
    f.write("										if (step_out==85) if (i_d==((in_dense)+1)) begin  dw=buff; we_w=1; weight_case=1; i_d=1; i1=i1+1; end\n")
    f.write("										case (weight_case)\n")
    f.write("											0: ;\n")
    f.write("											1: begin buff=0; buff[SIZE_weights*9-1:SIZE_weights*8]=data[SIZE_weights-1:0]; end \n")
    f.write("											2: buff[SIZE_weights*8-1:SIZE_weights*7]=data[SIZE_weights-1:0]; \n")
    f.write("											3: buff[SIZE_weights*7-1:SIZE_weights*6]=data[SIZE_weights-1:0];  \n")
    f.write("											4: buff[SIZE_weights*6-1:SIZE_weights*5]=data[SIZE_weights-1:0];  \n")
    f.write("											5: buff[SIZE_weights*5-1:SIZE_weights*4]=data[SIZE_weights-1:0];  \n")
    f.write("											6: buff[SIZE_weights*4-1:SIZE_weights*3]=data[SIZE_weights-1:0]; \n")
    f.write("											7: buff[SIZE_weights*3-1:SIZE_weights*2]=data[SIZE_weights-1:0]; \n")
    f.write("											8: buff[SIZE_weights*2-1:SIZE_weights]=data[SIZE_weights-1:0];   \n")
    f.write("											9: begin buff[SIZE_weights-1:0]=data[SIZE_weights-1:0]; end\n")
    f.write("											default: $display(\"Check weight_case\");\n")
    f.write("										endcase\n")
    f.write("										if (load_weights==1'b1) i_d=i_d+1;\n")
    f.write("										if (load_weights==1'b1)\n")
    f.write("											begin\n")
    f.write("												if ((weight_case==9)||((onexone)&&(weight_case==8))) \n")
    f.write("													begin \n")
    f.write("														weight_case=1; \n")
    f.write("														dw=buff; \n")
    f.write("														we_w=1; \n")
    f.write("														i1=i1+1;\n")
    f.write("													end \n")
    f.write("												else \n")
    f.write("													begin\n")
    f.write("														weight_case=weight_case+1;\n")
    f.write("													end\n")
    f.write("										end\n")
    f.write("                    end\n")
    f.write("					if (i>razn_addr+3)\n")
    f.write("                    begin\n")
    f.write("                        step=step+1;          //next step\n")
    f.write("                        i=0;\n")
    f.write("						i_d=0;\n")
    f.write("						i1=0;\n")
    f.write("						weight_case=0;\n")
    f.write("                    end\n")
    f.write("            end\n")
    f.write("			8'd2,8'd5,8'd8,8'd11,8'd14,8'd17,8'd20,8'd23,8'd26,8'd29,8'd32,8'd35,8'd38,8'd41,8'd44,8'd47,8'd50,8'd53,8'd56,8'd59,8'd62,8'd65,8'd68,8'd71,8'd74,8'd77,8'd80,8'd83:\n")
    f.write("				begin\n")
    f.write("					if (i<=razn_addr)\n")
    f.write("						begin\n")
    f.write("							we_bias=1;\n")
    f.write("							write_address_bias=addr;\n")
    f.write("							if (load_bias==1'b1) i=i+1;\n")
    f.write("							d_bias=data_bias;\n")
    f.write("						end\n")
    f.write("					else	\n")
    f.write("						begin\n")
    f.write("							step=step+1;\n")
    f.write("							i=0;\n")
    f.write("							we_bias=0;\n")
    f.write("						end\n")
    f.write("				end\n")
    f.write("			default:\n")
    f.write("				begin\n")
    f.write("					we_w=0;\n")
    f.write("					we_bias=0;\n")
    f.write("					i=0;\n")
    f.write("					i_d=0;\n")
    f.write("					i1=0;\n")
    f.write("				end\n")
    f.write("		endcase\n")
    f.write("    end\n")
    f.write("always @(posedge nextstep) if (GO==1) step_n=0; else step_n=step_n+1;\n")
    f.write("assign step_out=step+step_n;\n")
    f.write("assign address=(re_weights)?(firstaddr+i):0;\n")
    f.write("assign address_bias=(re_bias)?(firstaddr+i):0;\n")
    f.write("endmodule\n")

    f.close()

def result(directory,output_neurons_count,num_conv):
    f = open(directory + "result.v", 'w')

    bit_output_neurons_count = len(bin(output_neurons_count))-2
    bit_marker_chislo = len(bin(output_neurons_count+2)) - 2

    f.write("module result(clk,enable,STOP,memstartp,read_addressp,qp,re,RESULT);\n")
    f.write("\n")
    for i in range(num_conv):
        f.write("parameter SIZE_"+str(i+1)+"=0;\n")
    f.write("parameter SIZE_address_pix=0;\n")
    f.write("\n")
    f.write("input clk,enable;\n")
    f.write("output reg STOP;\n")
    f.write("input [SIZE_address_pix-1:0] memstartp;\n")
    f.write("input [SIZE_"+str(num_conv)+"-1:0] qp;\n")
    f.write("output reg re;\n")
    f.write("output reg [SIZE_address_pix-1:0] read_addressp;\n")
    f.write("output reg ["+str(bit_output_neurons_count-1)+":0] RESULT;\n")
    f.write("\n")
    f.write("reg ["+str(bit_marker_chislo-1)+":0] marker;\n")
    f.write("wire signed [SIZE_1-1:0] p1,p2;\n")
    f.write("always @(posedge clk)\n")
    f.write("begin\n")
    f.write("if (enable==1)\n")
    f.write("begin\n")
    f.write("re=1;\n")
    f.write("case (marker)\n")
    f.write("	0: read_addressp=memstartp;\n")
    f.write("	1: ;\n")
    f.write("	2: begin\n")
    f.write("		RESULT=0; \n")
    f.write("		if (p2>=p1) RESULT=1; \n")
    f.write("		else  RESULT=0; \n")
    f.write("		STOP=1; \n")
    f.write("		end\n")
    f.write("	default: $display(\"Check case result\");\n")
    f.write("endcase\n")
    f.write("marker=marker+1;\n")
    f.write("end\n")
    f.write("else \n")
    f.write("begin\n")
    f.write("re=0;\n")
    f.write("marker=0;\n")
    f.write("STOP=0;\n")
    f.write("end\n")
    f.write("end\n")
    f.write("\n")
    f.write("assign p1=qp[SIZE_" + str(num_conv) + "-1:SIZE_" + str(num_conv-1) + "];\n")
    f.write("assign p2=qp[SIZE_" + str(num_conv-1) + "-1:")
    if (num_conv-2!=0): f.write("SIZE_" + str(num_conv-2))
    else: f.write("0")
    f.write("];\n")
    f.write("endmodule\n")

def TOP(directory, sizeI, sizeW, sizeB, razmer, max_address_value, output_neurons_count, max_weights_per_layer,
        total_conv_layers_number, max_conv_input_size, in_dense_razmer,
        out_dense_razmer, max_conv_output_size, layers, num_conv, steps_count):
    f = open(directory + "TOP.v", 'w')

    bit_max_address_value = len(bin(max_address_value)) - 2
    bit_output_neurons_count = len(bin(output_neurons_count)) - 2
    bit_address_pix = len(bin(razmer*razmer*8+razmer*razmer)) - 2
    bit_address_pix_t = len(bin(razmer*razmer*4)) - 2
    bit_max_weights_per_layer = len(bin(max_weights_per_layer)) - 2
    bit_total_conv_layers_number = len(bin(total_conv_layers_number)) - 2
    bit_max_conv_input_size = len(bin(max_conv_input_size)) - 2
    bit_razmer = len(bin(razmer)) - 2
    bit_razmer_2 = len(bin(razmer*razmer)) - 2
    bit_in_dense_razmer = len(bin(in_dense_razmer)) - 2
    bit_out_dense_razmer = len(bin(out_dense_razmer)) - 2
    bit_max_conv_output_size = len(bin(max_conv_output_size)) - 2
    bit_steps_count = len(bin(steps_count)) - 2
    Y=''
    p=''
    w=''
    p_d=''
    w_c=''
    w_d=''
    for i in range(num_conv):
        Y=Y+"Y"+str(i+1)+","
        w_c=w_c+"w"+str(i+1)+"1_c,w"+str(i+1)+"2_c,w"+str(i+1)+"3_c,w"+str(i+1)+"4_c,w"+str(i+1)+"5_c,w"+str(i+1)+"6_c,w"+str(i+1)+"7_c,w"+str(i+1)+"8_c,w"+str(i+1)+"9_c,"
        w_d=w_d+"w"+str(i+1)+"1_d,w"+str(i+1)+"2_d,w"+str(i+1)+"3_d,w"+str(i+1)+"4_d,w"+str(i+1)+"5_d,w"+str(i+1)+"6_d,w"+str(i+1)+"7_d,w"+str(i+1)+"8_d,w"+str(i+1)+"9_d,"
        p_d=p_d+"p"+str(i+1)+"1_d,p"+str(i+1)+"2_d,p"+str(i+1)+"3_d,p"+str(i+1)+"4_d,p"+str(i+1)+"5_d,p"+str(i+1)+"6_d,p"+str(i+1)+"7_d,p"+str(i+1)+"8_d,p"+str(i+1)+"9_d,"
        p = p + "p" + str(i + 1) + "1,p" + str(i + 1) + "2,p" + str(i + 1) + "3,p" + str(i + 1) + "4,p" + str(i + 1) + "5,p" + str(i + 1) + "6,p" + str(i + 1) + "7,p" + str(i + 1) + "8,p" + str(i + 1) + "9,"
        w = w + "w" + str(i + 1) + "1,w" + str(i + 1) + "2,w" + str(i + 1) + "3,w" + str(i + 1) + "4,w" + str(i + 1) + "5,w" + str(i + 1) + "6,w" + str(i + 1) + "7,w" + str(i + 1) + "8,w" + str(i + 1) + "9,"

    f.write("module TOP(\n")
    f.write("clk,\n")
    f.write("clk_RAM_w,\n")
    f.write("clk_RAM_p,\n")
    f.write("GO,\n")
    f.write("RESULT,\n")
    f.write("STOP,\n")
    f.write("\n")
    f.write("re_weights,\n")
    f.write("load_weights,\n")
    f.write("dp_weights,\n")
    f.write("address_weights,\n")
    f.write("\n")
    f.write("re_bias,\n")
    f.write("load_bias,\n")
    f.write("dp_bias,\n")
    f.write("address_bias,\n")
    f.write("\n")
    f.write("we_image,\n")
    f.write("dp_image,\n")
    f.write("address_image,\n")
    f.write("step\n")
    f.write(");\n")
    f.write("\n")
    f.write("parameter num_conv="+str(num_conv)+";\n")
    f.write("parameter SIZE_weights = "+str(sizeW+1)+";\n")
    f.write("parameter SIZE_bias = "+str(sizeB+1)+";\n")
    for i in range(num_conv):
        f.write("parameter SIZE_"+ str(i+1) +"=" + str((sizeI + 1)*(i+1)) + ";\n")
    f.write("parameter SIZE_address_pix="+str(bit_address_pix)+";\n")
    f.write("parameter SIZE_address_pix_t="+str(bit_address_pix_t)+";\n")
    f.write("parameter SIZE_address_wei="+str(bit_max_weights_per_layer)+";\n")
    f.write("parameter SIZE_address_image=16;\n")
    f.write("parameter picture_size = "+str(razmer)+";\n")
    f.write("parameter picture_storage_limit = 0;\n")
    f.write("parameter razmpar = picture_size >> 1;\n")
    f.write("parameter razmpar2  = picture_size >> 2;\n")
    f.write("parameter picture_storage_limit_2 = picture_size*picture_size;\n")
    f.write("input clk,clk_RAM_w,clk_RAM_p;\n")
    f.write("input GO;\n")
    f.write("output ["+str(bit_output_neurons_count-1)+":0] RESULT;\n")
    f.write("input signed [SIZE_weights-1:0] dp_weights;\n")
    f.write("input signed [SIZE_bias-1:0] dp_bias;\n")
    f.write("output [23:0] address_weights;\n")
    f.write("output [11:0] address_bias;\n")
    f.write("input load_weights,load_bias;\n")
    f.write("input signed [SIZE_1-1:0] dp_image;\n")
    f.write("input [SIZE_address_image-1:0] address_image;\n")
    f.write("input we_image;\n")
    f.write("output reg STOP;\n")
    f.write("output re_weights,re_bias;\n")
    f.write("output ["+str(bit_steps_count-1)+":0] step;\n")
    f.write("\n")
    f.write("wire [SIZE_address_image-1:0] address_image_1;\n")
    f.write("\n")
    f.write("reg conv_en;\n")
    f.write("wire STOP_conv;\n")
    f.write("\n")
    f.write("reg dense_en;\n")
    f.write("wire STOP_dense;\n")
    f.write("\n")
    f.write("reg result_en;\n")
    f.write("wire STOP_res;	\n")
    f.write("wire ["+str(bit_output_neurons_count-1)+":0] res_out;\n")
    f.write("\n")
    f.write("reg bias,glob_average_en;\n")
    f.write("\n")
    f.write("reg ["+str(bit_total_conv_layers_number-1)+":0] TOPlvl_conv;\n")
    f.write("wire ["+str(bit_total_conv_layers_number-1)+":0] TOPlvl;\n")
    f.write("reg [8:0] lvl;\n")
    f.write("reg [8:0] slvl;\n")
    f.write("reg [2:0] num;\n")
    f.write("reg [SIZE_address_pix-1:0] memstartp;\n")
    f.write("wire [SIZE_address_pix-1:0] memstartp_lvl;\n")
    f.write("reg [SIZE_address_wei-1:0] memstartw;\n")
    f.write("wire [SIZE_address_wei-1:0] memstartw_lvl;\n")
    f.write("reg [SIZE_address_pix-1:0] memstartzap;\n")
    f.write("wire [SIZE_address_pix-1:0] memstartzap_num;\n")
    f.write("wire [10:0] 				memstartb;\n")
    f.write("wire [SIZE_address_pix-1:0] read_addressp;\n")
    f.write("wire [SIZE_address_image-1:0] read_addressp_init;\n")
    f.write("wire [SIZE_address_pix_t-1:0] read_addresstp;\n")
    f.write("wire [SIZE_address_wei-1:0] read_addressw;\n")
    f.write("wire [10:0]					read_address_bias; \n")
    f.write("wire [SIZE_address_pix-1:0] read_addressp_conv;\n")
    f.write("wire [SIZE_address_pix-1:0] read_addressp_dense;\n")
    f.write("wire [SIZE_address_pix-1:0] read_addressp_res;\n")
    f.write("wire [SIZE_address_wei-1:0] read_addressw_conv;\n")
    f.write("wire [SIZE_address_wei-1:0] read_addressw_dense;\n")
    f.write("wire [SIZE_address_pix-1:0] write_addressp;\n")
    f.write("wire [SIZE_address_pix_t-1:0] write_addresstp;\n")
    f.write("wire [SIZE_address_wei-1:0] write_addressw;\n")
    f.write("wire [10:0]					write_address_bias; \n")
    f.write("wire [SIZE_address_pix-1:0] write_addressp_zagr;\n")
    f.write("wire [SIZE_address_pix-1:0] write_addressp_conv;\n")
    f.write("wire [SIZE_address_pix-1:0] write_addressp_dense;\n")
    f.write("wire we_p,we_tp,we_w;\n")
    f.write("wire re_p,re_tp,re_w,re_p_init;\n")
    f.write("wire re_bias_RAM;\n")
    f.write("wire we_p_zagr;\n")
    f.write("wire we_conv,re_wb_conv,re_conv;\n")
    f.write("wire we_dense,re_p_dense,re_w_dense;\n")
    f.write("wire we_bias;\n")
    f.write("wire re_p_res;\n")
    f.write("wire signed [SIZE_"+str(num_conv)+"-1:0] qp;\n")
    f.write("wire signed [32*"+str(num_conv)+"-1:0] qtp;\n")
    f.write("wire signed [SIZE_weights*9-1:0] qw;\n")
    f.write("wire signed [SIZE_bias-1:0]	q_bias;\n")
    f.write("wire signed [SIZE_"+str(num_conv)+"-1:0] dp;\n")
    f.write("wire signed [32*"+str(num_conv)+"-1:0] dtp;\n")
    f.write("wire signed [SIZE_weights*9-1:0] dw;\n")
    f.write("wire signed [SIZE_"+str(num_conv)+"-1:0] dp_conv;\n")
    f.write("wire signed [SIZE_"+str(num_conv)+"-1:0] dp_dense;\n")
    f.write("wire signed [SIZE_"+str(num_conv)+"-1:0] dp_zagr;\n")
    f.write("wire signed [SIZE_bias-1:0] d_bias;\n")
    f.write("\n")
    f.write("wire [1:0] prov;\n")
    f.write("wire ["+str(bit_razmer_2-1)+":0] i_conv;\n")
    f.write("wire signed [32-1:0] ")
    for i in range(num_conv):
        f.write("Y"+str(i+1))
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("\n")
    f.write("wire signed [SIZE_weights-1:0] ")
    for i in range(num_conv):
        f.write("w"+str(i+1)+"1,w"+str(i+1)+"2,w"+str(i+1)+"3")
        if (i!=num_conv-1): f.write(",")
    f.write(";\n")
    f.write("wire signed [SIZE_weights-1:0] ")
    for i in range(num_conv):
        f.write("w"+str(i+1)+"1_c,w"+str(i+1)+"2_c,w"+str(i+1)+"3_c")
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("wire signed [SIZE_weights-1:0] ")
    for i in range(num_conv):
        f.write("w"+str(i+1)+"1_d,w"+str(i+1)+"2_d,w"+str(i+1)+"3_d")
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("wire signed [SIZE_1-1:0] ")
    for i in range(num_conv):
        f.write("p"+str(i+1)+"1,p"+str(i+1)+"2,p"+str(i+1)+"3")
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("wire signed [SIZE_1-1:0] ")
    for i in range(num_conv):
        f.write("p"+str(i+1)+"1_c,p"+str(i+1)+"2_c,p"+str(i+1)+"3_c")
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("wire signed [SIZE_1-1:0] ")
    for i in range(num_conv):
        f.write("p"+str(i+1)+"1_d,p"+str(i+1)+"2_d,p"+str(i+1)+"3_d")
        if (i != num_conv - 1): f.write(",")
    f.write(";\n")
    f.write("wire go_conv;\n")
    f.write("wire go_conv_TOP;\n")
    f.write("wire go_dense;\n")
    f.write("\n")
    f.write("reg nextstep;\n")
    f.write("\n")
    f.write("reg ["+str(bit_razmer-1)+":0] matrix;\n")
    f.write("wire ["+str(bit_razmer_2-1)+":0] matrix2;    //razmer*razmer\n")
    f.write("\n")
    f.write("reg ["+str(bit_max_conv_output_size-1)+":0] mem;\n")
    f.write("reg ["+str(bit_max_conv_input_size-1)+":0] filt;\n")
    f.write("reg [1:0] stride;\n")
    f.write("reg depthwise;\n")
    f.write("reg onexone;\n")
    f.write("\n")
    f.write("reg ["+str(bit_in_dense_razmer-1)+":0] in_dense;\n")
    f.write("reg ["+str(bit_out_dense_razmer-1)+":0] out_dense;\n")
    f.write("reg nozero_dense;\n")
    f.write("\n")
    f.write("wire clk_RAM;\n")
    f.write("\n")
    f.write("wire up_perm,down_perm;\n")
    f.write("wire [SIZE_address_pix-1:0] stride_plus_prov;\n")
    f.write("\n")
    f.write("conv_TOP #(\n")
    for i in range(num_conv):
        f.write("	SIZE_"+ str(i+1) +",\n")
    f.write("	SIZE_address_pix,\n")
    f.write("	SIZE_address_pix_t,\n")
    f.write("	SIZE_address_wei,\n")
    f.write("	SIZE_weights,\n")
    f.write("	SIZE_bias\n")
    f.write(") conv_TOP (\n")
    f.write("	.clk							(clk),\n")
    f.write("	.conv_en						(conv_en),\n")
    f.write("	.STOP							(STOP_conv),\n")
    f.write("	.memstartp					(memstartp_lvl),\n")
    f.write("	.memstartw					(memstartw_lvl),\n")
    f.write("	.memstartb					(memstartb),\n")
    f.write("	.memstartzap				(memstartzap_num),\n")
    f.write("	.read_addressp				(read_addressp_conv),\n")
    f.write("	.write_addressp			    (write_addressp_conv),\n")
    f.write("	.read_addresstp			    (read_addresstp),\n")
    f.write("	.write_addresstp			(write_addresstp),\n")
    f.write("	.read_addressb				(read_address_bias),\n")
    f.write("   .read_addressw				(read_addressw_conv),\n")
    f.write("	.we							(we_conv),\n")
    f.write("	.re_wb						(re_wb_conv),\n")
    f.write("	.re							(re_conv),\n")
    f.write("	.we_t						(we_tp),\n")
    f.write("	.re_t						(re_tp),\n")
    f.write("	.qp							(qp),\n")
    f.write("	.qtp						(qtp),\n")
    f.write("	.qw							(qw),\n")
    f.write("	.q_bias						(q_bias),\n")
    f.write("	.dp							(dp_conv),\n")
    f.write("	.dtp						(dtp),\n")
    f.write("	.prov						(prov),\n")
    f.write("	.matrix						(matrix),\n")
    f.write("	.matrix2					(matrix2),\n")
    f.write("	.i_to_prov					(i_conv),\n")
    f.write("	.lvl						(lvl),\n")
    f.write("	.slvl						(slvl),\n")
    for i in range(num_conv):
        f.write("	.Y"+str(i+1)+"							(Y"+str(i+1)+"),\n")
    for i in range(num_conv):
        for j in range(3):
            f.write("	.w"+str(i+1)+str(j+1)+"							(w"+str(i+1)+str(j+1)+"_c),\n")
    for i in range(num_conv):
        for j in range(3):
            f.write("	.p"+str(i)+"_"+str(j+1)+"							(p"+str(i+1)+str(j+1)+"_c),\n")
    f.write("	.go							(go_conv_TOP),\n")
    f.write("	.up_perm					(up_perm),\n")
    f.write("	.down_perm					(down_perm),\n")
    f.write("	.stride_plus_prov			(stride_plus_prov),\n")
    f.write("	.num						(num),\n")
    f.write("	.filt						(filt),\n")
    f.write("	.mem						(mem),\n")
    f.write("	.bias						(bias),\n")
    f.write("	.glob_average_en			(glob_average_en),\n")
    f.write("	.step						(step),\n")
    f.write("	.stride						(stride),\n")
    f.write("	.depthwise					(depthwise),\n")
    f.write("	.onexone					(onexone)\n")
    f.write(");\n")
    f.write("memorywork #(\n")
    f.write("	num_conv,\n")
    for i in range(num_conv):
        f.write("	SIZE_"+ str(i+1) +",\n")
    f.write("	SIZE_address_pix,\n")
    f.write("	SIZE_address_wei,\n")
    f.write("	SIZE_weights,\n")
    f.write("	SIZE_bias\n")
    f.write(") block (\n")
    f.write("	.clk_RAM_w					(clk_RAM_w),\n")
    f.write("	.we_w						(we_w),\n")
    f.write("	.re_weights					(re_weights),\n")
    f.write("	.re_bias					(re_bias),\n")
    f.write("	.load_weights				(load_weights),\n")
    f.write("	.addrw						(write_addressw),\n")
    f.write("	.dw							(dw),\n")
    f.write("	.step_out					(step),\n")
    f.write("	.nextstep					(nextstep),\n")
    f.write("	.data						(dp_weights),\n")
    f.write("	.address					(address_weights),\n")
    f.write("	.GO							(GO),\n")
    f.write("	.in_dense					(in_dense),\n")
    f.write("	.onexone					(onexone),\n")
    f.write("	.data_bias					(dp_bias),\n")
    f.write("	.load_bias					(load_bias),\n")
    f.write("	.address_bias				(address_bias),\n")
    f.write("	.write_address_bias		    (write_address_bias),\n")
    f.write("	.we_bias					(we_bias),\n")
    f.write("	.d_bias						(d_bias)\n")
    f.write(");\n")
    f.write("RAM #(\n")
    f.write("	picture_size,\n")
    for i in range(num_conv):
        f.write("	SIZE_"+ str(i+1) +",\n")
    f.write("	SIZE_address_pix,\n")
    f.write("	SIZE_address_pix_t,\n")
    f.write("	SIZE_address_wei,\n")
    f.write("	SIZE_address_image,\n")
    f.write("	SIZE_weights,\n")
    f.write("	SIZE_bias\n")
    f.write(") memory (\n")
    f.write("	.qp							(qp),\n")
    f.write("	.qtp						(qtp),\n")
    f.write("	.qw							(qw),\n")
    f.write("	.dp							(dp),\n")
    f.write("	.dtp						(dtp),\n")
    f.write("	.dw							(dw),\n")
    f.write("	.write_addressp			    (write_addressp),\n")
    f.write("	.read_addressp				(read_addressp),\n")
    f.write("	.write_addresstp			(write_addresstp),\n")
    f.write("	.read_addresstp			    (read_addresstp),\n")
    f.write("	.write_addressw			    (write_addressw),\n")
    f.write("	.read_addressw				(read_addressw),\n")
    f.write("	.we_p						(we_p),\n")
    f.write("	.we_tp						(we_tp),\n")
    f.write("	.we_w						(we_w),\n")
    f.write("	.re_p						(re_p),\n")
    f.write("	.re_tp						(re_tp),\n")
    f.write("	.re_w						(re_w),\n")
    f.write("	.clk						(clk_RAM),\n")
    f.write("	.clk_RAM_w					(clk_RAM_w),\n")
    f.write("	.q_bias						(q_bias),\n")
    f.write("	.d_bias						(d_bias),\n")
    f.write("	.we_bias					(we_bias),\n")
    f.write("	.re_bias					(re_bias_RAM),\n")
    f.write("	.write_address_bias		    (write_address_bias),\n")
    f.write("	.read_address_bias		    (read_address_bias)\n")
    f.write(");\n")
    f.write("border border(\n")
    f.write("	.clk						(clk),\n")
    f.write("	.go							(conv_en && (!onexone)),\n")
    f.write("	.i							(i_conv),\n")
    f.write("	.matrix						(matrix),\n")
    f.write("	.prov						(prov)\n")
    f.write(");\n")
    f.write("dense #(\n")
    f.write("	num_conv,\n")
    for i in range(num_conv):
        f.write("	SIZE_"+ str(i+1) +",\n")
    f.write("	SIZE_address_pix,\n")
    f.write("	SIZE_address_wei,\n")
    f.write("	SIZE_weights\n")
    f.write(") dense (\n")
    f.write("	.clk						(clk),\n")
    f.write("	.dense_en					(dense_en),\n")
    f.write("	.STOP						(STOP_dense),\n")
    f.write("	.in							(in_dense),\n")
    f.write("	.out						(out_dense),\n")
    f.write("	.we							(we_dense),\n")
    f.write("	.re_p						(re_p_dense),\n")
    f.write("	.re_w						(re_w_dense),\n")
    f.write("	.read_addressp				(read_addressp_dense),\n")
    f.write("	.read_addressw				(read_addressw_dense),\n")
    f.write("	.write_addressp			    (write_addressp_dense),\n")
    f.write("	.memstartp					(memstartp_lvl),\n")
    f.write("	.memstartzap				(memstartzap_num),\n")
    f.write("	.qp							(qp),\n")
    f.write("	.qw							(qw),\n")
    f.write("	.res						(dp_dense),\n")
    for i in range(num_conv):
        f.write("	.Y"+str(i+1)+"							(Y"+str(i+1)+"),\n")
    for i in range(num_conv):
        f.write("	.w"+str(i+1)+"1						(w"+str(i+1)+"1_d),\n")
        f.write("	.w"+str(i+1)+"2						(w"+str(i+1)+"2_d),\n")
        f.write("	.w"+str(i+1)+"3						(w"+str(i+1)+"3_d),\n")
    for i in range(num_conv):
        f.write("	.p" + str(i + 1) + "1						(p" + str(i + 1) + "1_d),\n")
        f.write("	.p" + str(i + 1) + "2						(p" + str(i + 1) + "2_d),\n")
        f.write("	.p" + str(i + 1) + "3						(p" + str(i + 1) + "3_d),\n")
    f.write("	.go							(go_dense),\n")
    f.write("	.nozero						(nozero_dense)\n")
    f.write(");\n")
    f.write("result #(\n")
    for i in range(num_conv):
        f.write("	SIZE_"+ str(i+1) +",\n")
    f.write("	SIZE_address_pix\n")
    f.write(") result (\n")
    f.write("	.clk						(clk),\n")
    f.write("	.enable						(result_en),\n")
    f.write("	.STOP						(STOP_res),\n")
    f.write("	.memstartp					(memstartp_lvl),\n")
    f.write("	.read_addressp				(read_addressp_res),\n")
    f.write("	.qp							(qp),\n")
    f.write("	.re							(re_p_res),\n")
    f.write("	.RESULT						(res_out)\n")
    f.write(");\n")
    for i in range(num_conv):
        f.write("conv #(\n")
        f.write("	SIZE_1,\n")
        f.write("	SIZE_address_pix,\n")
        f.write("	SIZE_weights\n")
        f.write(") conv"+str(i+1)+" (\n")
        f.write("	.clk						(clk),\n")
        f.write("	.Y1							(Y"+str(i+1)+"),\n")
        f.write("	.prov						(prov),\n")
        f.write("	.matrix						(matrix),\n")
        f.write("	.matrix2					(matrix2),\n")
        f.write("	.i							(i_conv),\n")
        f.write("	.up_perm					((up_perm && (!dense_en))),\n")
        f.write("	.down_perm					((down_perm && (!dense_en))),\n")
        f.write("	.p1							(p"+str(i+1)+"1),\n")
        f.write("	.p2							(p"+str(i+1)+"2),\n")
        f.write("	.p3							(p"+str(i+1)+"3),\n")
        f.write("	.w1							(w"+str(i+1)+"1),\n")
        f.write("	.w2							(w"+str(i+1)+"2),\n")
        f.write("	.w3							(w"+str(i+1)+"3),\n")
        f.write("	.conv_en					(go_conv),\n")
        f.write("	.dense_en					((onexone||dense_en)),\n")
        f.write("	.stride_plus_prov			(stride_plus_prov)\n")
        f.write(");\n")
    f.write("always @(posedge clk )\n")
    f.write("begin\n")
    f.write("if (GO==1)\n")
    f.write("begin\n")
    f.write("STOP=0;\n")
    f.write("nextstep=1;\n")
    f.write("glob_average_en=0;\n")
    f.write("result_en=0;\n")
    f.write("end\n")
    f.write("else nextstep=0;\n")
    f.write("if (STOP==0)\n")
    f.write("begin\n")

    TOPlvl = 1
    step = 0
    start = 1
    start_me = 0
    onexone = 0
    ZeroPadding2D = 0
    GlobalAveragePooling2D = 0
    one = "picture_storage_limit"
    two = "picture_storage_limit_2"
    for i in range(len(layers)):
        layer = str(layers[i].__class__.__name__)
        #print(layer,layers[i].input_shape,layers[i].output_shape)
        if 'Conv2D' in layer:
            if (str(layers[i+2].__class__.__name__) == 'GlobalAveragePooling2D'):   GlobalAveragePooling2D=1
            else: GlobalAveragePooling2D=0
            for j in range(1+GlobalAveragePooling2D):
                mem = int(layers[i].output_shape[3]/(1+GlobalAveragePooling2D)-1)
                filt = layers[i].input_shape[3]-1

                if (start == 0):
                    f.write("	    if ((TOPlvl=="+str(TOPlvl)+")&&(step=="+str(step)+")) \n")
                    f.write("           begin\n")
                    f.write("               nextstep = 1;\n")
                    f.write("               onexone = " + str(onexone) + ";\n")
                    f.write("           end\n")
                else: start = 0

                step += 3

                f.write("	    if ((TOPlvl=="+str(TOPlvl)+")&&(step=="+str(step)+"))\n")
                f.write("		    begin\n")
                if (ZeroPadding2D): f.write("			    matrix = "+str(layers[i].input_shape[1] - 1)+";\n")
                else: f.write("			    matrix = "+str(layers[i].input_shape[1])+";\n")
                f.write("			    memstartp = "+str(one)+";\n")
                f.write("			    memstartw = 0;\n")
                if (GlobalAveragePooling2D): f.write("			    memstartzap = "+str(two)+ "+" + str(j*int(128/num_conv)) + ";\n")
                else: f.write("			    memstartzap = "+str(two)+";\n")
                f.write("			    conv_en = 1;\n")
                f.write("			    dense_en=0;\n")
                if (start_me == 0):
                    f.write("			    mem = "+str(mem)+";\n")
                    f.write("			    filt = "+str(filt)+";\n")
                else:
                    f.write("			    mem = "+str(filt)+";\n")
                    f.write("			    filt = "+str(mem)+";\n")
                f.write("			    stride=" + str(layers[i].strides[0]) + ";\n")
                f.write("			    onexone=" + str(onexone) + ";\n")
                if (layer == 'DepthwiseConv2D'):
                    f.write("			    depthwise=1;\n")
                    if (GlobalAveragePooling2D == 0): onexone = 1
                else:
                    f.write("			    depthwise=0;\n")
                    if (GlobalAveragePooling2D == 0): onexone = 0
                if (GlobalAveragePooling2D): f.write("			    glob_average_en=1;\n")
                else: f.write("			    glob_average_en=0;\n")
                f.write("           end\n")

                if (j == GlobalAveragePooling2D):
                    one_t=one
                    two_t=two
                    two=one_t
                    one=two_t
                TOPlvl += 1
                start_me = 1
                ZeroPadding2D=0

        if 'ZeroPadding2D' in layer: ZeroPadding2D = 1
        if 'Dense' in layer:

            f.write("	    if ((TOPlvl==" + str(TOPlvl) + ")&&(step==" + str(step) + ")) \n")
            f.write("           begin\n")
            f.write("			    nextstep=1;\n")
            f.write("			    onexone=0;\n")
            f.write("			    in_dense="+str(layers[i].input_shape[1])+";\n")
            f.write("			    out_dense="+str(layers[i].output_shape[1])+";\n")
            f.write("			end\n")

            step += 2

            f.write("	    if ((TOPlvl=="+str(TOPlvl)+")&&(step=="+str(step)+"))\n")
            f.write("           begin\n")
            f.write("			    memstartp= " + str(one) + ";\n")
            f.write("			    memstartzap = " + str(two) + ";\n")
            f.write("			    conv_en=0;\n")
            f.write("			    dense_en=1;\n")
            f.write("			    nozero_dense=1;\n")
            f.write("			    depthwise=0;\n")
            f.write("			end\n")

            one_t=one
            two_t=two
            two=one_t
            one=two_t
            TOPlvl += 1
        if (i == len(layers)-1):
            step += 1
            f.write("	    if ((TOPlvl=="+str(TOPlvl-1)+")&&(STOP_dense==0)&&(step=="+str(step)+"))\n")
            f.write("		    begin\n")
            f.write("			    memstartp = "+str(one)+";\n")
            f.write("		    	result_en = 1;\n")
            f.write("		    end\n")

    f.write("	if ((depthwise)||(lvl==filt)||((onexone)&&(mem==((lvl+1)*8)-1))) bias=1; else bias=0;\n")
    f.write("	if ((STOP_conv)&&(conv_en==1)) conv_en=0;\n")
    f.write("	if (STOP_dense==1) begin dense_en=0; nextstep=1; end\n")
    f.write("	if ((STOP_res==1)&&(result_en==1))\n")
    f.write("	begin\n")
    f.write("		result_en=0;\n")
    f.write("		STOP=1;\n")
    f.write("	end\n")
    f.write("end\n")
    f.write("end\n")
    f.write("\n")
    f.write("always @(negedge STOP_conv or posedge GO)\n")
    f.write("	begin\n")
    f.write("		if (GO)\n")
    f.write("			begin\n")
    f.write("				lvl=0;\n")
    f.write("				slvl=0;\n")
    f.write("				TOPlvl_conv=1;\n")
    f.write("				num=0;\n")
    f.write("			end\n")
    f.write("		else\n")
    f.write("			begin\n")
    f.write("				if (lvl==(filt)||((lvl==filt>>"+ str(len(bin(num_conv))-3) +")&&(depthwise))||((lvl==((mem+1)>>3)-1)&&(onexone)))\n")
    f.write("					begin\n")
    f.write("						lvl=0;\n")
    f.write("						if ((num!=")
    if (num_conv<=4): f.write("4-num_conv")
    else: f.write("0")
    f.write(")&&(!depthwise)) num=num+1; else num=0;\n")
    f.write("						if ((num==0)||(depthwise))\n")
    f.write("						begin \n")
    f.write("							if ((depthwise)||((!onexone)&&(mem==("+str(num_conv)+"+(slvl*"+str(num_conv)+"))-1))||((onexone)&&(filt==("+str(num_conv)+"+(slvl*"+str(num_conv)+"))-1))) \n")
    f.write("								begin\n")
    f.write("									slvl=0; \n")
    f.write("									TOPlvl_conv=TOPlvl_conv+1'b1;\n")
    f.write("								end\n")
    f.write("							else slvl = slvl + 1'b1;\n")
    f.write("						end\n")
    f.write("					end\n")
    f.write("				else\n")
    f.write("				lvl=lvl+1;\n")
    f.write("			end\n")
    f.write("	end\n")
    f.write("\n")
    f.write("assign address_image_1 = address_image[")
    if (num_conv<3): f.write(str(bit_razmer_2-len(bin(num_conv))+3))
    else: f.write(str(13))
    f.write(":0]+1;	\n")
    f.write("\n")
    f.write("assign memstartw_lvl=memstartw+((onexone?num*(((mem+1)>>3)-1)+lvl:(depthwise?lvl*num_conv:lvl))+(((!depthwise)&&(!onexone))?(slvl*(4*(filt+1))):(1'b0))+((!onexone)?(num*(filt+1)):num+slvl*((mem+1)")
    if (num_conv<=4): f.write(">>"+str(len(bin(8-num_conv))-3))
    else: f.write("<<"+str(len(bin(num_conv-8))-3))
    f.write(")));\n")
    f.write("assign memstartzap_num = memstartzap+((glob_average_en)?(num+slvl*1):0)+(((conv_en==1)&&(!glob_average_en))?(num*((matrix>>(stride-1))*(matrix>>(stride-1)))+slvl*((matrix>>(stride-1))*(matrix>>(stride-1)))")
    if (num_conv<=4): f.write("*(5-num_conv)")
    f.write("+((depthwise)?lvl*((matrix>>(stride-1))*(matrix>>(stride-1))):0)):0);\n")
    f.write("assign memstartp_lvl=memstartp+(onexone?((lvl")
    if (num_conv>4): f.write("[8:"+str(len(bin(num_conv))-6)+"]")
    f.write(")*matrix2")
    if (num_conv<=4): f.write("*(8>>2)")
    f.write("):(depthwise?(lvl*matrix2):((lvl>>num_conv-1)*matrix2))); \n")
    f.write("assign memstartb=slvl*"+str(num_conv)+"+num+(depthwise?lvl*num_conv:0)+1;\n")
    f.write("\n")
    f.write("assign re_p=GO?1'b1:((conv_en==1)?re_conv:((dense_en==1)?re_p_dense:((result_en==1)?re_p_res:0)));\n")
    f.write("assign re_w=(conv_en==1)?re_wb_conv:((dense_en==1)?re_w_dense:0);\n")
    f.write("assign re_bias_RAM=(conv_en==1)?re_wb_conv:0;\n")
    f.write("assign read_addressp=GO?address_image_1[")
    if (num_conv < 3):
        f.write(str(bit_razmer_2 - len(bin(num_conv)) + 3))
    else:
        f.write(str(13))
    f.write(":0]:((conv_en==1)?read_addressp_conv:((dense_en==1)?read_addressp_dense:((result_en==1)?read_addressp_res:0)));\n")
    f.write("assign we_p=GO?we_image:((conv_en==1)?we_conv:((dense_en==1)?we_dense:0));\n")
    f.write("assign dp=GO?")
    n = 0
    for i in range(3):   #ИСПРАВИТЬ НА ЗАВИСИМОСТЬ (картинка 3-х цветная)
        f.write("((address_image<128*128*" + str(i+1) + ")?")
        f.write("{")
        for j in range(num_conv):
            if (j==n): f.write("dp_image")
            elif ((j>i)|(j==num_conv-1)): f.write(str(sizeI+1)+"'d0")
            else: f.write("qp[SIZE_"+str(num_conv-j)+"-1:SIZE_"+str(num_conv-j-1)+"]")
            if (j+1!=num_conv): f.write(",")
        if (n<num_conv-1): n=n+1
        else: n=0
        f.write("}")
        f.write(":")
        if (i+1==3): f.write("0))):")
    f.write("((conv_en==1)?dp_conv:((dense_en==1)?dp_dense:0));\n")
    f.write("assign write_addressp=GO?(address_image[")
    if num_conv < 3:
        f.write(str(bit_razmer_2 - len(bin(num_conv)) + 3))
    else:
        f.write(str(13))
    f.write(":0]):((conv_en==1)?write_addressp_conv:((dense_en==1)?write_addressp_dense:0));\n")
    f.write("assign read_addressw=(conv_en==1)?read_addressw_conv:((dense_en==1)?read_addressw_dense:0);\n")
    f.write("\n")
    f.write("assign matrix2=matrix*matrix;\n")
    f.write("\n")
    f.write("assign clk_RAM=GO?clk_RAM_p:clk;\n")
    f.write("\n")
    for i in range(num_conv):
        for j in range(3):
            f.write("assign p" + str(i+1) + str(j+1) + "=(conv_en==1)?p" + str(i+1) + str(j+1) + "_c:((dense_en==1)?p" + str(i+1) + str(j+1) + "_d:0);\n")
    f.write("\n")
    for i in range(num_conv):
        for j in range(3):
            f.write("assign w" + str(i+1) + str(j+1) + "=(conv_en==1)?w" + str(i+1) + str(j+1) + "_c:((dense_en==1)?w" + str(i+1) + str(j+1) + "_d:0);\n")
    f.write("\n")
    f.write("assign TOPlvl=TOPlvl_conv;\n")
    f.write("\n")
    f.write("assign go_conv=(conv_en==1)?go_conv_TOP:((dense_en==1)?go_dense:0);\n")
    f.write("\n")
    f.write("assign RESULT=(STOP)?res_out:4'b1111;\n")
    f.write("\n")
    f.write("endmodule\n")
    f.close()


if __name__ == '__main__':
    output_directory = os.path.join(ROOT_PATH, "verilog")

    nn_type = 'people'
    # nn_type = 'animals'
    # nn_type = 'cars'
    num_conv = 8

    if nn_type == 'people':
        model_path = MODEL_PATH + 'weights_mobilenet_1_0.25_128px_people_loss_0.3600_acc_0.8442_epoch_38_reduced_rescaled.h5'
        image_bit_precision, weight_bit_precision, bias_bit_precision, convW, convB = 12, 11, 10, 7, 3
    elif nn_type == 'animals':
        model_path = MODEL_PATH + 'weights_mobilenet_1_0.25_128px_animals_loss_0.2486_acc_0.8967_epoch_33_reduced_rescaled.h5'
        image_bit_precision, weight_bit_precision, bias_bit_precision, convW, convB = 12, 11, 10, 7, 3
    elif nn_type == 'cars':
        model_path = MODEL_PATH + 'weights_mobilenet_1_0.25_128px_cars_loss_0.1088_acc_0.9631_epoch_67_reduced_rescaled.h5'
        image_bit_precision, weight_bit_precision, bias_bit_precision, convW, convB = 12, 11, 10, 7, 3

    # Count of data in database: initial image and all weights (filled later)
    max_address_value = 0
    # Maximum weights for all layers, divided by 9, because all weights packed by 9 numbers, to be called in one tact.
    max_weights_per_layer = 0
    # Number of convolution layers
    total_conv_layers_number = 0
    # Number of dense (FC) layers
    total_dense_layers_number = 0

    print('Read model...')
    model = get_model(model_path)

    conv_inputs = []
    conv_blocks = []
    conv_mem = []
    conv_filt = []
    dense_inputs = []
    dense_outputs = []
    ZeroPadding2D = 0
    for i in range(len(model.layers)):
        layer = model.layers[i]
        if 'Input' in str(layer.__class__.__name__):
            input = layer.input_shape[1]*layer.input_shape[2]
        elif 'Conv2D' in str(layer.__class__.__name__):
            total_conv_layers_number += 1
            if ZeroPadding2D == 1:
                conv_inputs.append(layer.input_shape[1] - 1)
                ZeroPadding2D = 0
            else: conv_inputs.append(layer.input_shape[1])
            conv_mem.append(layer.input_shape[3])
            conv_filt.append(layer.output_shape[3])
            w = layer.get_weights()
            conv_block_size_1 = len(w[0])
            conv_block_size_2 = len(w[0][0])
            conv_blocks.append(conv_block_size_1)
            max_address_value += len(w[0][0][0][0])*len(w[0][0][0])*len(w[0][0])*len(w[0])
            max_weights_per_layer_1 = len(w[0][0][0][0])*len(w[0][0][0])
            if max_weights_per_layer_1 > max_weights_per_layer:
                max_weights_per_layer = max_weights_per_layer_1
        elif 'Dense' in str(layer.__class__.__name__):
            w = layer.get_weights()
            total_dense_layers_number += 1
            dense_inputs.append(layer.input_shape[1])
            dense_outputs.append(layer.output_shape[1])
            max_address_value += len(layer.get_weights()[0][0]) * len(w[0])
            max_weights_per_layer_1 = int(len(w[0][0]) * len(w[0])/(conv_block_size_1*conv_block_size_2)) + 1
            if max_weights_per_layer_1 > max_weights_per_layer:
                max_weights_per_layer = max_weights_per_layer_1
        if i == len(model.layers) - 1:
            # Number of neurons on final classification layer.
            output_neurons_count = layer.output_shape[1]

        if 'ZeroPadding2D' in str(layer.__class__.__name__):
            ZeroPadding2D = 1

    # Maximum size of image for neural net. Equal to 128.
    max_input_image_size = max(conv_inputs)
    # Number of steps in neural net. Step means any action like loading data, processing convolution layer.
    steps_count = 2 + (total_conv_layers_number*3) + (total_dense_layers_number*2) + 1
    # Bit size of input data for dense layer
    in_dense_size = max(dense_inputs)
    # Bit size of output data for dense layer
    out_dense_size = max(dense_outputs)
    # Size of convolution block.
    conv_block_size = max(conv_blocks)
    # Maximum number of input feature maps for all convolution layers
    max_conv_input_size = max(conv_filt)
    # Maximum number of output feature maps for all convolution layers
    max_conv_output_size = max(conv_mem)
    max_address_value += input

    print("Make addressRAM file")
    addressRAM(output_directory, steps_count, max_address_value)

    print("Make border file")
    border(output_directory, max_input_image_size)

    print("Make conv_block file")
    conv_block(output_directory,max_input_image_size)

    print("Make conv_TOP file")
    conv_TOP(output_directory, max_input_image_size, max_conv_input_size, max_conv_output_size, num_conv, steps_count,image_bit_precision,weight_bit_precision+convW)

    print("Make dense file")
    dense(output_directory, in_dense_size, out_dense_size, num_conv, image_bit_precision, weight_bit_precision+convW)

    print("Make RAM file")
    RAM(output_directory, max_weights_per_layer, num_conv)

    print("Make RAMtoMEM file")
    RAMtoMEM(output_directory, max_address_value, steps_count, in_dense_size, conv_block_size, num_conv)

    print("Make result file")
    result(output_directory, output_neurons_count, num_conv)

    TOP(output_directory, image_bit_precision, weight_bit_precision+convW, bias_bit_precision+convB, max_input_image_size, max_address_value, output_neurons_count,
        max_weights_per_layer, total_conv_layers_number, max_conv_input_size,
        in_dense_size, out_dense_size, max_conv_output_size, model.layers, num_conv, steps_count)


